I have lines in many directions and angles, I draw them using UIBezierpath
.
I need to draw an arrow on one of the ends of the line; dynamically depending on given point.
Edit:
Edit 2: with Jake answer here is my code
let y2 = line.point2Y
let path = UIBezierPath()
path.move(to: CGPoint(x: x1, y: y1))
path.addLine(to: CGPoint(x: x2, y: y2))
path.addArrow(start: CGPoint(x: x1, y: y1), end: CGPoint(x: x2, y: y2), pointerLineLength: ...
path.close()
let shape = CAShapeLayer()
let shapeBorder = CAShapeLayer()
shapeBorder.strokeColor = UIColor.black.cgColor
shapeBorder.lineJoin = kCALineJoinRound
shapeBorder.lineCap = kCALineCapRound
shapeBorder.lineWidth = 10
shapeBorder.addSublayer(shape)
shape.path = path.cgPath
shapeBorder.path = shape.path
shape.lineJoin = kCALineJoinRound
shape.lineCap = kCALineCapRound
shape.lineWidth = shapeBorder.lineWidth-5.0
shape.strokeColor = color
But there is a shadow
This works for me:
extension UIBezierPath {
func addArrow(start: CGPoint, end: CGPoint, pointerLineLength: CGFloat, arrowAngle: CGFloat) {
self.move(to: start)
self.addLine(to: end)
let startEndAngle = atan((end.y - start.y) / (end.x - start.x)) + ((end.x - start.x) < 0 ? CGFloat(Double.pi) : 0)
let arrowLine1 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle + arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle + arrowAngle))
let arrowLine2 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle - arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle - arrowAngle))
self.addLine(to: arrowLine1)
self.move(to: end)
self.addLine(to: arrowLine2)
}
}
class MyViewController : UIViewController {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let arrow = UIBezierPath()
arrow.addArrow(start: CGPoint(x: 200, y: 200), end: CGPoint(x: 50, y: 50), pointerLineLength: 30, arrowAngle: CGFloat(Double.pi / 4))
let arrowLayer = CAShapeLayer()
arrowLayer.strokeColor = UIColor.black.cgColor
arrowLayer.lineWidth = 3
arrowLayer.path = arrow.cgPath
arrowLayer.fillColor = UIColor.clear.cgColor
arrowLayer.lineJoin = kCALineJoinRound
arrowLayer.lineCap = kCALineCapRound
self.view.layer.addSublayer(arrowLayer)
}
}
EDIT
Also, make sure you set your the fillColor
of your CAShapeLayer
to UIColor.clear.cgColor
. Otherwise, your layer will fill in the area between the start point of the arrow and one of the lines at the end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With