Home > Back-end >  [iOS]Triangle shape with UIBezierPath in drawRect not working
[iOS]Triangle shape with UIBezierPath in drawRect not working

Time:12-09

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

CodePudding user response:

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 100x100 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()

CodePudding user response:

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

  • Related