在我的
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 似乎被推送到导航堆栈上,但在屏幕中不可见。
有什么建议这种奇怪行为的起源吗?
为您的导航控制器实现
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
实施
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
}
这应该可以解决问题,而无需在项目的每个视图中手动启用/禁用手势识别器。
来自 Guilherme Carvalho 的解决方案对我有用,但我必须在
viewWillAppear
中分配委托方法,在 viewDidLoad
中对于我的实现来说太晚了。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.interactivePopGestureRecognizer?.delegate = self
navigationController?.delegate = self
}
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
self.interactivePopGestureRecognizer?.isEnabled = self.viewControllers.count > 1
}
更新了 Swift 5 的@rivera 解决方案
在您的基础导航控制器中将委托设置为 self
self.interactivePopGestureRecognizer?.delegate = self
然后添加以下委托函数
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if viewControllers.count <= 1 {
return false
} else {
return true
}
}
试试这个代码
func navigationController(navigationController: UINavigationController, didShowViewController vc: UIViewController, animated: Bool) {
self.interactivePopGestureRecognizer?.enabled = self.vc.count > 1
}