interactivePopGestureRecognizer破坏根视图控制器上的导航堆栈

时间:2016-01-09 19:36:22

标签: swift uinavigationcontroller uigesturerecognizer

在我的UINavigationController我添加了自定义后退按钮,其副作用是不再可以从左向右滑动以弹出视图控制器并导航回来。

所以我在自定义interactivePopGestureRecognizer课程中实施了UINavigationController

class UINavigationControllerExtended: UINavigationController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        if self.respondsToSelector(Selector("interactivePopGestureRecognizer")) {
            self.interactivePopGestureRecognizer?.delegate = self
        }
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return gestureRecognizer.isKindOfClass(UIScreenEdgePanGestureRecognizer)
    }
}

这种方法很好,除非我在我的根视图控制器(RVC)中是UICollectionViewController,即导航堆栈中最底层的视图控制器。当我从左到右滑动手势时,似乎没有任何事情发生,正如预期的那样。但是当我点击UICollectionViewCell时,目标视图控制器(DVC)不会被推过RVC。相反,我只在屏幕右侧看到DVC的阴影。

RVC不再响应,但当我再次从左向右滑动时,DVC以交互方式从右向左移动到屏幕中。当我完成手势时,DVC完全移动到屏幕中,以便从左到右快速消失。 RVC再次响应。

所以看起来DVC被推到了导航堆栈上但没有明显地进入屏幕。

这种奇怪行为的起源是什么建议?

5 个答案:

答案 0 :(得分:5)

我目前的解决方案是禁用根视图控制器中的interactivePopGestureRecognizer

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    self.navigationController?.interactivePopGestureRecognizer?.enabled = false
}

在第一个子视图控制器中,我再次启用它。但这似乎更像是一种解决方法,因为我不了解导航堆栈首先搞砸的实际问题。

答案 1 :(得分:3)

为导航控制器实施UINavigationControllerDelegate并在那里启用/禁用手势识别器。

// Fix bug when pop gesture is enabled for the root controller
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
    self.interactivePopGestureRecognizer?.enabled = self.viewControllers.count > 1
}

保持代码独立于推送的视图控制器。

答案 2 :(得分:2)

这是我的解决方案。 Swift 4.2

实施UIGestureRecognizerDelegateUINavigationControllerDelegate协议。就我而言,我是在UITabBarController上执行此操作的,它也是我的根视图控制器。

然后在viewDidLoad上执行:

override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    self.navigationController?.delegate = self
}

然后,为UINavigationControllerDelegate添加委托方法,并通过计算导航控制器上的视图数来检查它是否为根视图,如果不是,则将其禁用,否则将其启用。

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    let enable = self.navigationController?.viewControllers.count ?? 0 > 1
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = enable
}

最后,添加UIGestureRecognizerDelegate方法

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

这应该可以解决问题,而无需在项目的每个视图中手动启用/禁用手势识别器。

答案 3 :(得分:0)

func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
    self.interactivePopGestureRecognizer?.isEnabled = self.viewControllers.count > 1
}

更新的Swift 5 @rivera解决方案

答案 4 :(得分:-2)

Swift 3
首先上课:

import UIKit

class Total: NSObject,UIGestureRecognizerDelegate {

    //MARK:_Swip
    func backSwipVC(_ pr:UIViewController) {
        pr.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
        pr.navigationController?.interactivePopGestureRecognizer?.delegate = self
    }

}  

并在 viewDidLoad() 中调用此内容:

Total().backSwipVC(self)