import Foundation import UIKit class DrawingGestureRecognizer: UIPanGestureRecognizer { var shouldBegin: (CGPoint) -> Bool = { _ in return true } override func touchesBegan(_ touches: Set, with event: UIEvent) { if touches.count == 1, let touch = touches.first, self.shouldBegin(touch.location(in: self.view)) { super.touchesBegan(touches, with: event) self.state = .began } } override func touchesMoved(_ touches: Set, with event: UIEvent) { if touches.count > 1 { self.state = .cancelled } else { super.touchesMoved(touches, with: event) } } } struct DrawingPoint { let location: CGPoint let velocity: CGFloat var x: CGFloat { return self.location.x } var y: CGFloat { return self.location.y } } final class DrawingGesturePipeline: NSObject, UIGestureRecognizerDelegate { enum DrawingGestureState { case began case changed case ended case cancelled } var onDrawing: (DrawingGestureState, DrawingPoint) -> Void = { _, _ in } var gestureRecognizer: DrawingGestureRecognizer? var transform: CGAffineTransform = .identity var enabled: Bool = true weak var drawingView: DrawingView? init(drawingView: DrawingView, gestureView: UIView) { self.drawingView = drawingView super.init() let gestureRecognizer = DrawingGestureRecognizer(target: self, action: #selector(self.handleGesture(_:))) gestureRecognizer.delegate = self self.gestureRecognizer = gestureRecognizer gestureView.addGestureRecognizer(gestureRecognizer) } func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return self.enabled } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { if otherGestureRecognizer is UIPinchGestureRecognizer { return true } return false } var previousPoint: DrawingPoint? @objc private func handleGesture(_ gestureRecognizer: DrawingGestureRecognizer) { let state: DrawingGestureState switch gestureRecognizer.state { case .began: state = .began case .changed: state = .changed case .ended: state = .ended case .cancelled: state = .cancelled case .failed: state = .cancelled case .possible: state = .cancelled @unknown default: state = .cancelled } let originalLocation = gestureRecognizer.location(in: self.drawingView) let location = originalLocation.applying(self.transform) let velocity = gestureRecognizer.velocity(in: self.drawingView).applying(self.transform) let velocityValue = velocity.length let point = DrawingPoint(location: location, velocity: velocityValue) self.onDrawing(state, point) } }