在Swift中禁用向右滑动返回手势

84

我在这里看了一段时间,但似乎找不到可行的解决方案。

我正在尝试在Swift中禁用向后滑动以返回上一个视图的手势。

我已经尝试了各种解决方案,包括:

self.navigationController?.interactivePopGestureRecognizer.enabled = false

self.navigationController.interactivePopGestureRecognizer.delegate = self

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
    return false
}

有没有新方法可以做到这一点?或者还有其他可行的方法吗?


1
当用户没有完全滑动时,它会导致问题,并干扰我们正在使用的UI的本质(在音频轨道中寻找时间)。 - Phil Hudson
1
好的,我不想偏离你的问题,但我建议你(1)解决不能完全滑动的问题,(2)缩进音频轨道寻找UI,这样它就不会太靠近边缘。这是预期的用户体验,对于iPhone 6 Plus和iPad用户尤其重要,因为他们很难到达导航栏。 - Aaron Brager
无论如何,你的代码应该禁用手势识别器。它在旧版本的iOS上工作吗? - Aaron Brager
啊,关于 iPhone 6 的问题,你说得很好 - 或许我会考虑修改 dealloc 方法 - 但我仍然会保持问题的开放性,因为我仍然很感兴趣。 - Phil Hudson
我正在iOS 8上进行最低测试。 - Phil Hudson
我能够通过在gestureRecognizerShouldBegin中返回false来实现它。你是否在gestureRecognizerShouldBegin收到回调?也许你把这段代码放错了视图控制器... - Hari Kunwar
16个回答

185
以下是一个简单的方法来禁用和重新启用滑动返回。
Swift 3.x及以上版本:
在viewDidLoad/willAppear/didAppear方法中添加:
navigationController?.interactivePopGestureRecognizer?.isEnabled = false

请记住,如果你在viewDidLoad中这样做,那么下一次打开视图时,它可能不会设置,具体取决于它是否保留在您的栈中。

除非您希望其保持关闭状态,否则您需要通过willMove(toParentViewController:)willDisappear重新打开视图关闭时。在viewDidDisappear时,您的navigationController将为空,因此为时已晚。

navigationController?.interactivePopGestureRecognizer?.isEnabled = true

SplitViewControllers特别说明:

正如评论中CompC所指出的那样,您需要调用第二个导航控制器来将其应用于详细视图,如下所示:

navigationController?.navigationController?.interactivePopGe‌​stureRecognizer?.isE‌​nabled = false

Swift 2.2 & Objective-C

Swift版本2.x及以下:

navigationController?.interactivePopGestureRecognizer?.enabled

Objective-C:

self.navigationController.interactivePopGestureRecognizer.enabled

2
我在尝试禁用此功能的视图控制器位于分割视图控制器的详细信息侧面时遇到了一些麻烦,直到意识到它实际上位于单独的导航控制器中(即使在折叠时看起来像是在同一个控制器中)。为了解决这个问题,我不得不执行以下操作:`navigationController?.navigationController?.interactivePopGestureRecognizer?.isEnabled = false` - CompC
只需在didAppear中禁用它,在willDisappear上重新启用它即可。特别是在didDisappear上重新启用它是无用的,因为navigationController属性已经为nil。 - Vilém Kurz
3
谢谢,这应该是正确答案。 - Hernan Arber
1
@iajmeri43,创建UINavigationController的子类,然后在其viewDidLoad中设置属性。只要导航控制器被应用程序中想要的所有视图所使用,它就可以正常工作。 - CodeBender
我想指出的是,interactivePopGestureRecorgizer 可能没有初始化,具体取决于您尝试设置 navigationController?.interactivePopGestureRecognizer?.isEnabled = false 的时间和位置。我正在使用协调器,在初始化 NavController 之后并在推送第一个 ViewController 之前,这个值为 nil。 - TMin
显示剩余3条评论

23
我可以通过在gestureRecognizerShouldBegin中返回false来实现这一点。
class ViewController2: UIViewController, UIGestureRecognizerDelegate {
...
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    self.navigationController?.interactivePopGestureRecognizer.delegate = self
}

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    return false
}

请注意,OP的代码中有UIGestureRecognizer!,而这里是UIGestureRecognizer - Aaron Brager
它正在工作,谢谢@Hari Kunwar - Sanjay Shah

21
你可以禁用它,但不建议这样做,因为大多数iOS用户会通过滑动而不是按返回按钮返回。如果要禁用它,使用modal segue比使用push segue更合理,因为它的传输量不大。如果你真的想要去掉滑动返回功能,我建议仅禁用返回按钮并在屏幕右上角添加一个完成按钮。
self.navigationController?.navigationItem.backBarButtonItem?.isEnabled = false;

19
在将视图控制器推入导航控制器之前,请添加此行代码。
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

7

哈里和斯特凡的回答都没有问题,但这个更加简洁。只需将它放在viewDidLoad中即可完成。

if navigationController!.respondsToSelector(Selector("interactivePopGestureRecognizer")) {
    navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer)
}

编辑:

需要注意的一点是,如果导航控制器是由另一个视图打开的,并且导航控制器被关闭,则会出现EXC_BAD_ACCESS错误。要解决这个问题,您需要保存原始的UIGestureRecognizer,并在退出视图时将其放回。

声明:

private var popGesture: UIGestureRecognizer?

在移除手势之前立即执行以下操作:

popGesture = navigationController!.interactivePopGestureRecognizer

然后在关闭视图时:

If popGesture != nil {
    navigationController!.view.addGestureRecognizer(popGesture!)
}

5

不要使用

self.navigationController.pushViewController(VC, animated: Bool)

而是使用

self.navigationController.setViewContollers([VC], animated: Bool)

setViewControllers 替换掉 栈中所有的VC,而不仅是在堆栈顶添加一个新控制器。这意味着新设置的VC成为了根VC,用户无法返回。

当您只想禁用单个VC上的滑动手势,并保留其他VC的滑动返回时,此方法最有效。

如果您希望用户能够返回,但不能通过滑动手势返回,请不要使用此方法,因为它会禁用所有返回操作(由于没有可返回的VC)。


1
太好了!谢谢你! - Senocico Stelian

4

RowanPD的Swift 4逻辑

private var popGesture: UIGestureRecognizer?

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

    if navigationController!.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) {
        self.popGesture = navigationController!.interactivePopGestureRecognizer
        self.navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer!)
    }

}

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

    if let gesture = self.popGesture {
        self.navigationController!.view.addGestureRecognizer(gesture)
    }

}

3

如果您尝试了所有方法后仍然不起作用,那么可能是您忽略的问题。

  1. 在您的viewWillAppear(animated:)方法中添加navigationController?.interactivePopGestureRecognizer?.isEnabled = false
  2. 如果还不行,请从视图控制器中删除导航委托。检查您的视图控制器是否确认了UINavigationControllerDelegateUIGestureRecognizerDelegate协议,如果确认了,请直接将其删除。

3

针对Objective-C

-(void)viewWillAppear:(BOOL)animated{
  [super viewWillAppear:true];

  self.navigationController.interactivePopGestureRecognizer.enabled = NO;

}

2

我通常会尽可能多地启用“滑动返回”功能,甚至添加自定义手势识别器以在模态屏幕中添加它。然而,在我的应用程序中进行身份验证和下载过程时,我使用模态导航控制器开始该过程,然后推送每个下一步的视图。但是,一旦完成,我希望防止用户返回到身份验证屏幕。

对于这种情况,我一直在使用以下方法:

navigationController?.interactivePopGestureRecognizer?.isEnabled = false
navigationItem.hidesBackButton = true

在最后一个界面的viewWillAppear()方法中,您可以执行这些操作。如果您要推送到另一个视图并需要它们,请在viewWillDisappear()方法中撤销这些操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接