区分 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()
    }
}

此方法允许您在 willShowdidShow 中对 viewController 执行操作。您甚至可以将 UIViewController 子类化并添加 isBeingDismissedInteractively var,然后在 viewWillAppear 中检查 isBeingDismissedisMovingFromParentViewController但这对我来说太过分了。

希望这对某人有所帮助!

对于仍在寻找其他解决方案的任何人,我曾经检查过状态,但不要引用我的话

if self.navigationController?.interactivePopGestureRecognizer?.state == .began {
  // Gesture bagan 
}