skip to Main Content

I am trying to learn building custom shapes using UIBezierPath and I am trying to build a simple triangle. Below is the code I am using

class ViewController: UIViewController {

    let customView = CustomTraingleView(frame: CGRectZero)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(customView)
        customView.frame = CGRect(origin: CGPoint(x: 150, y: 200), size: CGSize(width: 100, height: 100))
    }
}

class CustomTraingleView: UIView
{
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.red
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        let viewSize = self.bounds.size
        let path = UIBezierPath()
        path.lineWidth = 3
        path.move(to: CGPoint(x: frame.origin.x + viewSize.width/2, y: frame.origin.y + viewSize.height/2))
        path.addLine(to: CGPoint(x: frame.origin.x + (3 * viewSize.width)/4, y: frame.origin.y + (3 * viewSize.height)/4))
        path.addLine(to: CGPoint(x: frame.origin.x + viewSize.width/2, y: frame.origin.y + (3 * viewSize.height)/4))
        UIColor.black.setStroke()
        path.stroke()
        path.close()
    }
}

I am not seeing any shape getting rendered. I am seeing a red bgColor with the view I am adding.

Could someone please take a look at this and let me know what I am missing here
enter image description here

2

Answers


  1. You have drawn the triangle relative to frame.origin, rather than to bounds.origin.

    frame, as you have set in viewDidLoad is x: 150, y: 200, so the triangle is will be drawn 150 points to the right, and 200 points below the top left corner of the red square. The red square is only 100×100 points, so that position is out of the bounds of the red square (and probably even off screen if your device is small), which is why you cannot see the triangle.

    In other words, in CustomTraingleView.draw, you are working in the coordinate system of CustomTriangleView, not the coordinate system of the view controller’s view. frame.origin is the origin point of the CustomTriangleView expressed in the coordinates of the superview’s coordinate system – the coordinates are relative to the superview’s origin. But you are drawing relative to CustomTraingleView‘s origin here!

    Therefore, you should change all those frames to bounds:

    path.move(to: CGPoint(x: bounds.origin.x + viewSize.width/2, y: bounds.origin.y + viewSize.height/2))
    path.addLine(to: CGPoint(x: bounds.origin.x + (3 * viewSize.width)/4, y: bounds.origin.y + (3 * viewSize.height)/4))
    path.addLine(to: CGPoint(x: bounds.origin.x + viewSize.width/2, y: bounds.origin.y + (3 * viewSize.height)/4))
    

    bounds.origin is the origin point of the view expressed in the coordinates of the view’s own coordinate system, exactly what we need here. By default, this is (0, 0).

    And you should also close the path first, then stroke it. Otherwise you only get two sides of the triangle 🙂

    path.close()
    path.stroke()
    
    Login or Signup to reply.
  2. Try this, declare your UIView:

    let myView = TriangleView()
    

    this i how your triangle class looks like:

    class TriangleView : UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override func draw(_ rect: CGRect) {
    
        guard let context = UIGraphicsGetCurrentContext() else { return }
    
        context.beginPath()
        context.move(to: CGPoint(x: rect.minX, y: rect.maxY))
        context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
        context.addLine(to: CGPoint(x: (rect.maxX / 2.0), y: rect.minY))
        context.closePath()
    
        context.setFillColor(red: 1.0, green: 0.5, blue: 0.0, alpha: 1) // fill color
        context.fillPath()
     }
    }
    

    In viewDidLoad set your view attribute and set constraints:

    myView.backgroundColor = .clear
    myView.translatesAutoresizingMaskIntoConstraints = false
        
     view.addSubview(myView)
        myView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        myView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        myView.heightAnchor.constraint(equalToConstant: 100).isActive = true
        myView.widthAnchor.constraint(equalToConstant: 100).isActive = true
    

    This is the result

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search