Swift
Many thanks a lot to Paul!!! Here is his Swift version:
import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {
var editorView: EditorView!
override func viewDidLoad() {
super.viewDidLoad()
let blueView = UIView(frame: .init(x: 100, y: 100, width: 300, height: 300))
view.addSubview(blueView)
blueView.backgroundColor = .blue
addMovementGesturesToView(blueView)
}
func addMovementGesturesToView(_ view: UIView) {
view.isUserInteractionEnabled = true
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
panGesture.delegate = self
view.addGestureRecognizer(panGesture)
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinchGesture(_:)))
pinchGesture.delegate = self
view.addGestureRecognizer(pinchGesture)
}
@objc private func handlePanGesture(_ panGesture: UIPanGestureRecognizer) {
guard let panView = panGesture.view else { return }
let translation = panGesture.translation(in: panView.superview)
if panGesture.state == .began || panGesture.state == .changed {
panGesture.view?.center = CGPoint(x: panView.center.x + translation.x, y: panView.center.y + translation.y)
// Reset translation, so we can get translation delta's (i.e. change in translation)
panGesture.setTranslation(.zero, in: self.view)
}
// Don't need any logic for ended/failed/canceled states
}
@objc private func handlePinchGesture(_ pinchGesture: UIPinchGestureRecognizer) {
guard let pinchView = pinchGesture.view else { return }
if pinchGesture.state == .began || pinchGesture.state == .changed {
let currentScale = scale(for: pinchView.transform)
// Variables to adjust the max/min values of zoom
let minScale: CGFloat = 0.2
let maxScale: CGFloat = 3
let zoomSpeed: CGFloat = 0.8
var deltaScale = pinchGesture.scale
// You need to translate the zoom to 0 (origin) so that you
// can multiply a speed factor and then translate back to "zoomSpace" around 1
deltaScale = ((deltaScale - 1) * zoomSpeed) + 1
// Limit to min/max size (i.e maxScale = 2, current scale = 2, 2/2 = 1.0)
// A deltaScale is ~0.99 for decreasing or ~1.01 for increasing
// A deltaScale of 1.0 will maintain the zoom size
deltaScale = min(deltaScale, maxScale / currentScale)
deltaScale = max(deltaScale, minScale / currentScale)
let zoomTransform = pinchView.transform.scaledBy(x: deltaScale, y: deltaScale)
pinchView.transform = zoomTransform
// Reset to 1 for scale delta's
// Note: not 0, or we won't see a size: 0 * width = 0
pinchGesture.scale = 1
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
private func scale(for transform: CGAffineTransform) -> CGFloat {
return sqrt(CGFloat(transform.a * transform.a + transform.c * transform.c))
}
}
Demo (on Simulator):