问题
I am creating an app that has a user interface similar to Tinder.
By this, I mean that there are three primary view controllers that can be "panned" between. The user can simply drag to move to any of the three view controllers.
I have implemented something similar in my app with one important caveat: it utilizes swipe gesture recognizers and not pan gesture recognizers.
The end-result looks and feels very unnatural.
This is how I'd like my user interface to behave (ignore the Gecko):
This is how it currently behaves with a swipe gesture recognizer:
Notice how with Tinder, you can pan to a new view controller without having completely committed the segue. And, if the pan hasn't displaced the current view controller beyond a minimum threshold, it will simply snap back into place. This is the behavior I am looking for.
Here is some code that I am currently using to mimic with a swipe gesture recognizer:
//The following logic is applied in a similar way to view controllers 1 and 3 as well.
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
addSwipeGestureRecognizers()
}
func addSwipeGestureRecognizers() {
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeLeft))
swipeLeft.direction = UISwipeGestureRecognizer.Direction.left
self.view.addGestureRecognizer(swipeLeft)
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeRight))
swipeRight.direction = UISwipeGestureRecognizer.Direction.right
self.view.addGestureRecognizer(swipeRight)
}
@objc func handleSwipeLeft() {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let viewController1 = storyboard.instantiateViewController(withIdentifier: "ViewController1") as! ViewController1
let transition:CATransition = CATransition()
transition.duration = 0.25
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromLeft
self.navigationController!.view.layer.add(transition, forKey: kCATransition)
navigationController!.pushViewController(viewController1, animated: false)
}
@objc func handleSwipeRight() {
let storyboard = UIStoryboard(name: "Main", bundle: .main)
let viewController3 = storyboard.instantiateViewController(withIdentifier: "ViewController3") as! ViewController3
let transition:CATransition = CATransition()
transition.duration = 0.25
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.type = CATransitionType.push
transition.subtype = CATransitionSubtype.fromRight
self.navigationController!.view.layer.add(transition, forKey: kCATransition)
navigationController!.pushViewController(viewController3, animated: false)
}
}
I am also utilizing a custom UIViewControllerAnimatedTransitioning
to make the pushed view controllers push the presenting view controller out from the left or right. This is done as opposed to the default stacking on top of the presenting view controller. I also have my UINavigationController
's navigation bar hidden.
回答1:
I'm not sure UINavigationController is the correct container controller to provide what you need. You might find that UIPageViewController is a better choice, I think it will provide the natural swipe gesture you are looking for out of the box, although it's quite an opaque class with some quirks of its own.
To go the custom route (either with UINavigationController or the more flexible/customisable UIViewController custom presentation) you are on the right track with UIViewControllerAnimatedTransitioning and the other (numerous) associated protocols. In case you are in a hurry, that route will take you quite a long time to implement, so maybe a simple UIPageViewController implementation will have to do for the moment.
回答2:
This project on github may help you in achieving your requirement - Here
来源:https://stackoverflow.com/questions/57504675/pan-not-swipe-between-view-controllers