简体   繁体   English

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

[英]interactivePopGestureRecognizer corrupts navigation stack on root view controller

In my UINavigationController I added custom back buttons with the side effect that it is not possible anymore to swipe left to right to pop the view controller and navigate back.在我的UINavigationController中,我添加了自定义后退按钮,其副作用是无法再从左向右滑动以弹出视图控制器并向后导航。

So I implemented interactivePopGestureRecognizer in my custom UINavigationController class:所以我在我的自定义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)
    }
}

This works fine except when I am in my root view controller (RVC) which is a UICollectionViewController , ie the most bottom view controller in the navigation stack.这工作正常,除非我在我的根视图控制器 (RVC) 中,它是一个UICollectionViewController ,即导航堆栈中最底部的视图控制器。 When I do the swipe left to right gesture, nothing seems to happen, as expected.当我做从左向右滑动的手势时,似乎没有发生任何事情,正如预期的那样。 But when I then tap a UICollectionViewCell the destination view controller (DVC) does not get pushed over the RVC.但是,当我随后点击 UICollectionViewCell 时,目标视图控制器 (DVC) 不会被推到 RVC 上。 Instead I only see the DVC's shadow on the right side of the screen.相反,我只在屏幕右侧看到 DVC 的影子。

The RVC is not responsive anymore, but as I swipe left to right again, the DVC interactively moves right to left into the screen. RVC 不再响应,但当我再次从左向右滑动时,DVC 交互地从右向左移动到屏幕中。 When I finish the gesture, the DVC moves completely into the screen just to quickly disappear left to right again.当我完成手势时,DVC 完全移入屏幕,然后再次从左到右快速消失。 The RVC becomes responsive again. RVC 再次响应。

So it seems the DVC gets pushed onto the navigation stack but not visibly into the screen.所以看起来 DVC 被推到导航堆栈上但没有明显地进入屏幕。

Any suggestions where this strange behaviour originates?这种奇怪行为的起源有什么建议吗?

Implement UINavigationControllerDelegate for your navigation controller and enable/disable the gesture recognizer there.为您的导航控制器实施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
}

Keeping the code independent from the pushed view controllers.保持代码独立于推送的视图控制器。

My current solution is to disable the interactivePopGestureRecognizer in the root view controller:我当前的解决方案是在根视图控制器中禁用interactivePopGestureRecognizer

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

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

In the first child view controller I enable it again.在第一个子视图控制器中,我再次启用它。 But this seems to be more a workaround because I don't understand the actual problem why the navigation stack got messed up in the first place.但这似乎更像是一种解决方法,因为我不明白为什么导航堆栈一开始就搞砸了的实际问题。

Here is my solution for this.这是我的解决方案。 Swift 4.2斯威夫特 4.2

Implement UIGestureRecognizerDelegate and UINavigationControllerDelegate protocols.实施UIGestureRecognizerDelegateUINavigationControllerDelegate协议。 In my case I did this in an UITabBarController that would be also my root view controller.在我的例子中,我在UITabBarController中执行了此操作,它也是我的根视图控制器。

Then, on viewDidLoad, do:然后,在 viewDidLoad 上执行:

override func viewDidLoad() {
    super.viewDidLoad()

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

Then, add the delegate method for UINavigationControllerDelegate and check if it is the root view by counting the number of view on the navigation controller and disable it if it is or enable it if its not.然后,为UINavigationControllerDelegate添加委托方法,并通过计算导航控制器上的视图数量来检查它是否是根视图,如果是则禁用它,如果不是则启用它。

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

Lastly, add the UIGestureRecognizerDelegate method最后,添加UIGestureRecognizerDelegate方法

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

This should fix the problem without the necessity of manually enabling/disabling the gesture recogniser in every view of your project.这应该可以解决问题,而无需在项目的每个视图中手动启用/禁用手势识别器。

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

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

Solution from Guilherme Carvalho worked for me, but I had to assign delegate methods in viewWillAppear , in viewDidLoad was too late for my implementation. Guilherme Carvalho的解决方案对我有用,但我必须在viewWillAppear中分配委托方法,在viewDidLoad中对我的实现来说为时已晚。

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

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

Try this code试试这个代码

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

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

相关问题 如何从根视图控制器到导航堆栈中的最后一个视图控制器快速执行segue? - how to perform segue from root view controller to the last view controller in the navigation stack in swift? InteractivePopGestureRecognizer弹出到根目录,而不是1个顶部控制器 - interactivePopGestureRecognizer pop to root instead of 1 top controller 关闭导航堆栈中任何加载的视图并返回到导航堆栈的根 - Dismiss any loaded view in a navigation stack and return to the root of navigation stack 在导航堆栈中模态显示视图控制器 - Presenting a view controller modally within a navigation stack 如何展开导航堆栈上的第一个视图控制器 - How to unwind to the first view controller on a navigation stack UINavigationController的方法将视图控制器添加到导航堆栈? - Method of UINavigationController to add a view controller to navigation stack? 在导航堆栈中跳过/添加视图控制器 - Skip/Add a View Controller in Navigation Stack 导航控制器如何弹出整个堆栈,包括根 - Navigation controller how to pop entire stack, including root 导航控制器作为根视图控制器只显示黑屏 - navigation controller as root view controller only displaying black screen ios swift - 解除导航控制器的根视图控制器 - ios swift - dismiss root view controller of navigation controller
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM