When it comes to drawing lines in Swift, most solutions out there are to override the drawRect function in a UIView, but I\'m looking for a more dynamic way to draw a line.<
You can use UIPanGestureRecognizer to get gesture events and draw a CALayer with UIBezierPath.
UIPanGestureRecognizer has some gesture states, in this case, we need to handle three states to draw the line. Let's separate the whole action into small pieces for more easier to figure out what to do.
Before the start, there is one thing you have to know.
// We can get current touch position via gesture recognizer.
let currentPanPoint = panRecognizer.location(in: self.view)
CALayer in state UIGestureRecognizerState.began.case .began:
panGestureStartPoint = currentPanPoint
self.view.layer.addSublayer(lineShape)
UIGestureRecognizerState.changed and create a UIBezierPath, assign the CGPath of UIBezierPath to CALayer to draw the line.case .changed:
let linePath = UIBezierPath()
linePath.move(to: panGestureStartPoint)
linePath.addLine(to: currentPanPoint)
lineShape.path = linePath.cgPath
UIGestureRecognizerState.end.case .ended:
lineShape.path = nil
lineShape.removeFromSuperlayer()
Combine the fragments above, here is the example code.
class ViewController: UIViewController {
@IBOutlet var dragFrom: UILabel!
private lazy var lineShape: CAShapeLayer = {
let lineShape = CAShapeLayer()
lineShape.strokeColor = UIColor.blue.cgColor
lineShape.lineWidth = 2.0
return lineShape
}()
private var panGestureStartPoint: CGPoint = .zero
private lazy var panRecognizer: UIPanGestureRecognizer = {
return UIPanGestureRecognizer(target: self, action: #selector(panGestureCalled(_:)))
}()
override func viewDidLoad() {
super.viewDidLoad()
self.dragFrom.addGestureRecognizer(panRecognizer)
}
// MARK: Selectors
func panGestureCalled(_: UIPanGestureRecognizer) {
let currentPanPoint = panRecognizer.location(in: self.view)
switch panRecognizer.state {
case .began:
panGestureStartPoint = currentPanPoint
self.view.layer.addSublayer(lineShape)
case .changed:
let linePath = UIBezierPath()
linePath.move(to: panGestureStartPoint)
linePath.addLine(to: currentPanPoint)
lineShape.path = linePath.cgPath
case .ended:
lineShape.path = nil
lineShape.removeFromSuperlayer()
default: break
}
}
}
And it works like this. http://i.imgur.com/5JsFeoB.gifv
If you wanna learn more details, this is the tutorial in Apple's Developer guides. Learn how to draw shapes using Bezier Path