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