Give priority to swipe
You can give priority to a UIGestureRecognizer
with the require(toFail:)
method.
@IBOutlet var myPanGestureRecognizer: UIPanGestureRecognizer!
@IBOutlet var mySwipeGestureRecognizer: UISwipeGestureRecognizer!
myPanGesture.require(toFail: mySwipeGestureRecognizer)
Now your pan will only execute if your swipe fails.
Use pan for everything
If the swipe and pan gesture recognizers don't play nicely with this setup, you can roll all of your logic into the pan gesture recognizer for more control.
let minHeight: CGFloat = 100
let maxHeight: CGFloat = 700
let swipeVelocity: CGFloat = 500
var previousTranslationY: CGFloat = 0
@IBOutlet weak var cardHeightConstraint: NSLayoutConstraint!
@IBAction func didPanOnCard(_ sender: Any) {
guard let panGesture = sender as? UIPanGestureRecognizer else { return }
let gestureEnded = bool(panGesture.state == UIGestureRecognizerState.ended)
let velocity = panGesture.velocity(in: self.view)
if gestureEnded && abs(velocity.y) > swipeVelocity {
handlePanOnCardAsSwipe(withVelocity: velocity.y)
} else {
handlePanOnCard(panGesture)
}
}
func handlePanOnCard(_ panGesture: UIPanGestureRecognizer) {
let translation = panGesture.translation(in: self.view)
let translationYDelta = translation.y - previousTranslationY
if abs(translationYDelta) < 1 { return } // ignore small changes
let newCardHeight = cardHeightConstraint.constant - translationYDelta
if newCardHeight > minHeight && newCardHeight < maxHeight {
cardHeightConstraint.constant = newCardHeight
previousTranslationY = translation.y
}
if panGesture.state == UIGestureRecognizerState.ended {
previousTranslationY = 0
}
}
func handlePanOnCardAsSwipe(withVelocity velocity: CGFloat) {
if velocity.y > 0 {
dismissCard() // implementation not shown
} else {
maximizeCard() // implementation not shown
}
}
Here's a demo of the above code in action.