问题
In modern user interfaces on iOS, it is often useful to implement multiple UIGestureRecognizers on a single view, in order to provide more realistic behavior of displayed objects that model the real world.
For example, you might want to be able to both drag a view around the screen, but also use two fingers to rotate it.
The UIGestureRecognizerDelegate
provides an optional function shouldRecognizeSimultaneouslyWith
for this purpose. Returning true
avoids only one gesture having effect at a time:
// MARK: - UIGestureRecognizerDelegate
extension GestureController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
However, when multiple gesture recognisers are active, especially UIRotationGestureRecognizer
it can be frustrating to find the view behaving unexpectedly as the handlers constantly override each other.
How can multiple gesture recognisers be implemented to provide smooth behavior?
回答1:
The key to implementing multiple gesture recognisers simultaneously is modifying their CGAffineTransforms
rather than overwriting them.
Apple > Documentation > Core Graphics > CGAffineTransform:
Note that you do not typically need to create affine transforms directly. If you want only to draw an object that is scaled or rotated, for example, it is not necessary to construct an affine transform to do so. The most direct way to manipulate your drawing—whether by movement, scaling, or rotation—is to call the functions translateBy(x:y:) , scaleBy(x:y:) , or rotate(by:) , respectively. You should generally only create an affine transform if you want to reuse it later.
Furthermore, when changes are detected, after applying the translation, it is important to reset the value of the sender, so that the translations do not compound each time they are detected.
For example:
@IBAction func rotateAction(_ sender: UIRotationGestureRecognizer) {
guard let view = sender.view else { return }
switch sender.state {
case .changed:
view.transform = view.transform.rotated(by: sender.rotation)
sender.rotation = 0
default: break
}
}
and
@IBAction func panAction(_ sender: UIPanGestureRecognizer) {
guard let view = sender.view else { return }
switch sender.state {
case .changed:
let translationX = sender.translation(in: view).x
let translationY = sender.translation(in: view).y
view.transform = view.transform.translatedBy(x: translationX, y: translationY)
sender.setTranslation(CGPoint.zero, in: view)
default: break
}
}
来源:https://stackoverflow.com/questions/44474496/using-multiple-uigesturerecognizers-simultaneously-like-uirotationgesturerecogni