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

问题描述 投票:0回答:7

在我的

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 似乎被推送到导航堆栈上,但在屏幕中不可见。

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

swift uinavigationcontroller uigesturerecognizer
7个回答
14
投票

为您的导航控制器实现

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
}

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


9
投票

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

interactivePopGestureRecognizer

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

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

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


7
投票

这是我的解决方案。斯威夫特 4.2

实施

UIGestureRecognizerDelegate
UINavigationControllerDelegate
协议。就我而言,我在
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
}

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


1
投票

来自 Guilherme Carvalho 的解决方案对我有用,但我必须在

viewWillAppear
中分配委托方法,在
viewDidLoad
中对于我的实现来说太晚了。

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

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

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

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


0
投票

在您的基础导航控制器中将委托设置为 self

self.interactivePopGestureRecognizer?.delegate = self

然后添加以下委托函数

  func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    if viewControllers.count <= 1 {
        return false
    } else {
        return true
    }
}

-2
投票

试试这个代码

func navigationController(navigationController: UINavigationController, didShowViewController vc: UIViewController, animated: Bool) {
    self.interactivePopGestureRecognizer?.enabled = self.vc.count > 1
}
© www.soinside.com 2019 - 2024. All rights reserved.