简体   繁体   中英

Make a pan gesture respond on vertical swipe downs

I implemented a pan gesture in my application to dismiss a view. Basically when a user swipes down, the view dismisses.

However, I want it to work so that it doesn't dismiss if a user swipes diagonally down, or semi-down. I only want it to be responsive on a strict vertical swipe down. Here is my code so far.

    var originalPosition: CGPoint?
    var currentPositionTouched: CGPoint?

func panGestureAction(_ panGesture: UIPanGestureRecognizer) {
    if currentScreen == 0 {
    let translation = panGesture.translation(in: view)

    if panGesture.state == .began {
         originalPosition = view.center
         //currentPositionTouched = panGesture.location(in: view)
    } else if panGesture.state == .changed {
           view.frame.origin = CGPoint(
            x:  view.frame.origin.x,
            y:  view.frame.origin.y + translation.y
        )
        panGesture.setTranslation(CGPoint.zero, in: self.view)
    } else if panGesture.state == .ended {
        let velocity = panGesture.velocity(in: view)
        if velocity.y >= 150 {
            UIView.animate(withDuration: 0.2
                , animations: {
                    self.view.frame.origin = CGPoint(
                        x: self.view.frame.origin.x,
                        y: self.view.frame.size.height
                    )
            }, completion: { (isCompleted) in
                if isCompleted {
                    self.dismiss(animated: false, completion: nil)
                }
            })
        } else {
            UIView.animate(withDuration: 0.2, animations: {
                self.view.center = self.originalPosition!
            })
        }
    }
    }
}

You are on the right track with currentPositionTouched . In your .began block, set currentPositionTouched to the panGesture 's location

currentPositionTouched = panGesture.location(in: view)

Then, in your .changed and .ended block, use a check to determine if the x value is the same and develop your logic accordingly.

if currentPositionTouched.x == panGesture.location(in: view).x

You can use gestureRecognizerShouldBegin . You can set it up to only recognize vertical gestures (ie those for which the angle is less than a certain size). For example, in Swift, it is:

extension ViewController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let gesture = gestureRecognizer as? UIPanGestureRecognizer else { return false }

        let translation = gesture.translation(in: gesture.view!)
        if translation.x != 0 || translation.y != 0 {
            let angle = atan2(abs(translation.x), translation.y)
            return angle < .pi / 8
        }
        return false
    }
}

Just make sure to set the delegate of the pan gesture recognizer.

Note, I'm not checking to see if it's absolutely vertical (because of variations in the gesture path, it will likely rarely be perfectly vertical), but within some reasonable angle from that.


FYI, this is based upon this Objective-C rendition .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM