Swift 3: Drawing a rectangle

58,438

Solution 1

In order to see the view, you need to create one and give it frame so that it knows how big to make it.

If you put your code in a Playground, and then add this line:

let d = Draw(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

You'll be able to click on the Quick View on the right, and then you'll see the view.

Yellow square in a playground


You can also add the view as a subview of view in your ViewController and then you'll see it on the iPhone:

override func viewDidLoad() {
    super.viewDidLoad()

    let k = Draw(frame: CGRect(
        origin: CGPoint(x: 50, y: 50),
        size: CGSize(width: 100, height: 100)))

    // Add the view to the view hierarchy so that it shows up on screen
    self.view.addSubview(k)
}

Note that you never call draw(_:) directly. It is called for you by Cocoa Touch to display the view.

Yellow square on iPhoneSE

Solution 2

Create a class, I put it in a separate Swift 3 file.

//
//  Plot_Demo.swift
//
//  Storyboard is not good in creating self adapting UI
//  Plot_Demo creates the drawing programatically.

import Foundation
import UIKit

public class Plot_Demo: UIView
{
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required public init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    public override func draw(_ frame: CGRect) {
        let h = frame.height
        let w = frame.width
        let color:UIColor = UIColor.yellow

        let drect = CGRect(x: (w * 0.25), y: (h * 0.25), width: (w * 0.5), height: (h * 0.5))
        let bpath:UIBezierPath = UIBezierPath(rect: drect)

        color.set()
        bpath.stroke()

        print("it ran")
        NSLog("drawRect has updated the view")
    }
}

Example of use in an UIViewController object:

override func viewDidLoad() {
    super.viewDidLoad()

    // Instantiate a new Plot_Demo object (inherits and has all properties of UIView)
    let k = Plot_Demo(frame: CGRect(x: 75, y: 75, width: 150, height: 150))

    // Put the rectangle in the canvas in this new object
    k.draw(CGRect(x: 50, y: 50, width: 100, height: 100))

    // view: UIView was created earlier using StoryBoard
    // Display the contents (our rectangle) by attaching it
    self.view.addSubview(k)
}

Run in an iPhone simulator and on an iPhone:

enter image description here

Used XCode Version 8.0 (8A218a), Swift 3, target iOS 10.0

Solution 3

This is another way of drawing Rectangle,

Step 1: Get rectangle path for given points

(Note: arrPathPoints must be 4 in count to draw rectangle),

func getPathPayer(arrPathPoints:[CGPoint]) throws -> CAShapeLayer {
        enum PathError : Error{
            case moreThan2PointsNeeded
        }

        guard arrPathPoints.count > 2 else {
            throw PathError.moreThan2PointsNeeded
        }

        let lineColor = UIColor.blue
        let lineWidth: CGFloat = 2
        let path = UIBezierPath()
        let pathLayer = CAShapeLayer()

        for (index,pathPoint) in arrPathPoints.enumerated() {
            switch index {
            //First point
            case 0:
                path.move(to: pathPoint)

            //Last point
            case arrPathPoints.count - 1:
                path.addLine(to: pathPoint)
                path.close()

            //Middle Points
            default:
                path.addLine(to: pathPoint)
            }
        }

        pathLayer.path = path.cgPath
        pathLayer.strokeColor = lineColor.cgColor
        pathLayer.lineWidth = lineWidth
        pathLayer.fillColor = UIColor.clear.cgColor

        return pathLayer
    }

Step 2: Usage, Call method like this,

override func viewDidLoad() {
        super.viewDidLoad()

        do {
            let rectangleLayer = try getPathPayer(arrPathPoints: [
                CGPoint(x: 110, y: 110),    //Top-Left
                CGPoint(x: 130, y: 110),    //Top-Right
                CGPoint(x: 130, y: 130),    //Bottom-Right
                CGPoint(x: 110, y: 130)])   //Bottom-Left
            view.layer.addSublayer(rectangleLayer)
        } catch {
            debugPrint(error)
        }
    }

Solution 4

My version of how to draw a rectangle using Swift 5.

First create a class to do the drawing. It uses CoreGraphics to do the drawing, rather than UIKit.

import UIKit

class DrawRectangle: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override func draw(_ rect: CGRect) {

        guard let context = UIGraphicsGetCurrentContext() else {
            print("could not get graphics context")
            return
        }

        context.setStrokeColor(UIColor.yellow.cgColor)
        context.setLineWidth(2)
        context.stroke(rect.insetBy(dx: 10, dy: 10))
    }
}

Then put this in your ViewController's viewDidLoad()

    let myView = DrawRectangle(frame: CGRect(x: 50, y: 50, width: 100, height: 100))

    self.view.addSubview(myView)
Share:
58,438
Jean Valjean
Author by

Jean Valjean

I eat rubber. Eggplant.

Updated on March 25, 2020

Comments

  • Jean Valjean
    Jean Valjean over 4 years

    I'm 3 days new to swift, and I'm trying to figure out how to draw a rectangle. I'm too new to the language to know the classes to extend and the methods to override, and I've looked around for sample code, but nothing seems to work (which I'm attributing to my use of swift 3).

    What I'm trying now is:

    import UIKit
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
    
            let k = Draw(frame: CGRect(
                origin: CGPoint(x: 50, y: 50),
                size: CGSize(width: 100, height: 100)))
    
            k.draw(CGRect(
                origin: CGPoint(x: 50, y: 50),
                size: CGSize(width: 100, height: 100)));
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
    
    }
    class Draw: UIView {
    
        override init(frame: CGRect) {
            super.init(frame: frame)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func draw(_ rect: CGRect) {
            let h = rect.height
            let w = rect.width
            var color:UIColor = UIColor.yellow()
    
            var drect = CGRect(x: (w * 0.25),y: (h * 0.25),width: (w * 0.5),height: (h * 0.5))
            var bpath:UIBezierPath = UIBezierPath(rect: drect)
    
            color.set()
            bpath.stroke()
    
            print("it ran")
    
            NSLog("drawRect has updated the view")
    
        }
    
    }
    

    And that's not doing anything. Help.

  • bshirley
    bshirley over 7 years
    From draw(_:) documentation: – You should never call this method directly yourself. To invalidate part of your view, and thus cause that portion to be redrawn, call the setNeedsDisplay() or setNeedsDisplay(_:) method instead.
  • Doug Null
    Doug Null about 3 years
    I get error: Cannot find 'Draw' in scope