繁体   English   中英

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

[英]interactivePopGestureRecognizer corrupts navigation stack on root view controller

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

所以我在我的自定义UINavigationController类中实现了interactivePopGestureRecognizer

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 被推到导航堆栈上但没有明显地进入屏幕。

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

为您的导航控制器实施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
}

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

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

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

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

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

这是我的解决方案。 斯威夫特 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
}

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

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

更新了 Swift 5 的@rivera 解决方案

Guilherme Carvalho的解决方案对我有用,但我必须在viewWillAppear中分配委托方法,在viewDidLoad中对我的实现来说为时已晚。

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

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

试试这个代码

func navigationController(navigationController: UINavigationController, didShowViewController vc: UIViewController, animated: Bool) {
    self.interactivePopGestureRecognizer?.enabled = self.vc.count > 1
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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