区分 UINavigation 栏后退按钮和交互式弹出滑动以返回?
Discern between UINavigation bar back button, and interactive pop swipe to go back?
我需要区分 iOS 中返回的两种方法 – 点击导航栏中的后退按钮,以及使用屏幕边缘平移来执行此操作。如果可能的话,我宁愿不实现自定义后退按钮。
我该如何解决这个问题?
想通了:
我已经实现了 UINavigationControllerDelegate
,将自己声明为该委托,并设置了一个名为 isPanningBack
的布尔值。然后实施了这家伙;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
[tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (![context isCancelled]) {
_isPanningBack = YES;
}
}];
}
然后,实施viewDidDisappear:animated
:
- (void)viewDidDisappear:(BOOL)animated
{
if (!_isPanningBack) {
// We can be sure that we used the chevron.
} else {
// We can be sure that we used the swipe.
}
[super viewDidDisappear:animated];
}
如果你像我一样尝试了上面的解决方案,但需要知道 before viewWillAppear
被调用,我想出了以下解决方案来区分 pops由后退按钮触发的和由交互式向后滑动触发的。
class SpendingCardContainedNavigationController: UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
private var poppingFromSwipe = false
override init(navigationBarClass: AnyClass?, toolbarClass: AnyClass?) {
super.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
delegate = self
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
// Prevents a known, albeit a rare, bug
guard viewControllers.count > 1 else { return false }
poppingFromSwipe = true
return true
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
interactivePopGestureRecognizer?.delegate = self
if !poppingFromSwipe {
viewController.doSomethingUseful()
}
poppingFromSwipe = false
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
interactivePopGestureRecognizer?.delegate = self
viewController.doSomethingElseUseful()
}
}
此方法允许您在 willShow
和 didShow
中对 viewController
执行操作。您甚至可以将 UIViewController
子类化并添加 isBeingDismissedInteractively
var
,然后在 viewWillAppear
中检查 isBeingDismissed
或 isMovingFromParentViewController
但这对我来说太过分了。
希望这对某人有所帮助!
对于仍在寻找其他解决方案的任何人,我曾经检查过状态,但不要引用我的话
if self.navigationController?.interactivePopGestureRecognizer?.state == .began {
// Gesture bagan
}
我需要区分 iOS 中返回的两种方法 – 点击导航栏中的后退按钮,以及使用屏幕边缘平移来执行此操作。如果可能的话,我宁愿不实现自定义后退按钮。
我该如何解决这个问题?
想通了:
我已经实现了 UINavigationControllerDelegate
,将自己声明为该委托,并设置了一个名为 isPanningBack
的布尔值。然后实施了这家伙;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
id<UIViewControllerTransitionCoordinator> tc = navigationController.topViewController.transitionCoordinator;
[tc notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
if (![context isCancelled]) {
_isPanningBack = YES;
}
}];
}
然后,实施viewDidDisappear:animated
:
- (void)viewDidDisappear:(BOOL)animated
{
if (!_isPanningBack) {
// We can be sure that we used the chevron.
} else {
// We can be sure that we used the swipe.
}
[super viewDidDisappear:animated];
}
如果你像我一样尝试了上面的解决方案,但需要知道 before viewWillAppear
被调用,我想出了以下解决方案来区分 pops由后退按钮触发的和由交互式向后滑动触发的。
class SpendingCardContainedNavigationController: UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate {
private var poppingFromSwipe = false
override init(navigationBarClass: AnyClass?, toolbarClass: AnyClass?) {
super.init(navigationBarClass: navigationBarClass, toolbarClass: toolbarClass)
delegate = self
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
delegate = self
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
// Prevents a known, albeit a rare, bug
guard viewControllers.count > 1 else { return false }
poppingFromSwipe = true
return true
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
interactivePopGestureRecognizer?.delegate = self
if !poppingFromSwipe {
viewController.doSomethingUseful()
}
poppingFromSwipe = false
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
interactivePopGestureRecognizer?.delegate = self
viewController.doSomethingElseUseful()
}
}
此方法允许您在 willShow
和 didShow
中对 viewController
执行操作。您甚至可以将 UIViewController
子类化并添加 isBeingDismissedInteractively
var
,然后在 viewWillAppear
中检查 isBeingDismissed
或 isMovingFromParentViewController
但这对我来说太过分了。
希望这对某人有所帮助!
对于仍在寻找其他解决方案的任何人,我曾经检查过状态,但不要引用我的话
if self.navigationController?.interactivePopGestureRecognizer?.state == .began {
// Gesture bagan
}