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
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 frame
s 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