如何禁用UINavigationController在iOS 7上的向后滑动手势

在iOS 7中,苹果增加了一个新的默认导航行为。你可以从屏幕的左边缘滑动回到导航堆栈。但在我的应用程序中,这种行为与我的自定义左侧菜单冲突。那么,是否有可能在UINavigationController中禁用这个新手势?

165743 次浏览

我找到了一个解决方案:

objective - c:

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
< p > 斯威夫特3 +: < br > self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false < / p >

我发现只把手势设置为禁用并不总是有效。它确实有用,但对我来说,只有在我用过一次后才起作用。第二次就不会触发手势了。

修复我是委托手势和实现shouldbegin方法返回NO:

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


// Disable iOS 7 back gesture
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}


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


// Enable iOS 7 back gesture
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}


- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return NO;
}

我对Twan的回答做了一些修改,因为:

  1. 你的视图控制器可以被设置为其他手势识别器的委托
  2. 将委托设置为nil会导致当你返回到根视图控制器并在导航到其他地方时做出滑动手势时挂起问题。

下面以iOS 7为例:

{
id savedGestureRecognizerDelegate;
}


- (void)viewWillAppear:(BOOL)animated
{
savedGestureRecognizerDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}


- (void)viewWillDisappear:(BOOL)animated
{
self.navigationController.interactivePopGestureRecognizer.delegate = savedGestureRecognizerDelegate;
}


- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer) {
return NO;
}
// add whatever logic you would otherwise have
return YES;
}

从iOS 8开始,接受的答案不再有效。我需要在我的主游戏屏幕上停止滑动来解散手势,所以执行了这个:

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


if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}


- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}


}


- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
return NO;
}

编辑

如果你想管理特定导航控制器的向后滑动功能,可以考虑使用SwipeBack

有了这个,你可以设置navigationController.swipeBackEnabled = NO

例如:

#import <SwipeBack/SwipeBack.h>


- (void)viewWillAppear:(BOOL)animated
{
navigationController.swipeBackEnabled = NO;
}

它可以通过CocoaPods安装。

pod 'SwipeBack', '~> 1.0'

我很抱歉没有解释清楚。

只需从NavigationController中删除手势识别器。在iOS 8中工作。

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)])
[self.navigationController.view removeGestureRecognizer:self.navigationController.interactivePopGestureRecognizer];

这适用于iOS 8的viewDidLoad::

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.navigationController.interactivePopGestureRecognizer.enabled = false;
});

很多问题都可以在dispatch_after的帮助下解决。

尽管请注意,这种解决方案可能不安全,但请使用自己的推理。

更新

对于iOS 8.1,延迟时间应该是0.5秒

在iOS 9.3上不再需要延迟,它只需要将此放在viewDidLoad中即可工作:
(iOS 9.0-9.3版本待定)

navigationController?.interactivePopGestureRecognizer?.enabled = false

没有一个给出的答案帮助我解决这个问题。在这里张贴我的答案;可能对某人有帮助

在你的视图控制器中声明private var popGesture: UIGestureRecognizer?为全局变量。然后在在viewDidAppearviewWillDisappear方法中实现代码

override func viewDidAppear(animated: Bool) {


super.viewDidAppear(animated)


if self.navigationController!.respondsToSelector(Selector("interactivePopGestureRecognizer")) {


self.popGesture = navigationController!.interactivePopGestureRecognizer
self.navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer!)
}
}




override func viewWillDisappear(animated: Bool) {


super.viewWillDisappear(animated)


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

这将禁用iOS v8.x以后的滑动回

所有这些解决方案都以一种他们不推荐的方式操纵苹果的手势识别器。我的一个朋友刚刚告诉我,有一个更好的解决方案:

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

其中myPanGestureRecognizer是你用来显示菜单的手势识别器。这样,当你按下一个新的导航控制器时,苹果的手势识别器就不会被重新打开,也不需要依赖黑客延迟,如果你的手机处于睡眠状态或负载过重,可能会过早触发。

把这个留在这里,因为我知道下次需要的时候我不会记得了,然后我就有了这个问题的解决方案。

我的方法。一个手势识别器来统治它们:

class DisabledGestureViewController: UIViewController: UIGestureRecognizerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.interactivePopGestureRecognizer!.delegate = self
}


func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
// Prevent going back to the previous view
return !(navigationController!.topViewController is DisabledGestureViewController)
}
}

重要:不要在导航堆栈中的任何地方重置委托:navigationController!.interactivePopGestureRecognizer!.delegate = nil

迅速:

navigationController!.interactivePopGestureRecognizer!.enabled = false

它适用于我的ios 10和更高版本:

- (void)viewWillAppear:(BOOL)animated {
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}


}

它在viewDidLoad()方法上不起作用。

这是Swift 3的方式

对我有用

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

请在root vc下设置:

-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:YES];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;


}


-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:YES];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}

对于斯威夫特4,这是有效的:

class MyViewController: UIViewController, UIGestureRecognizerDelegate {


override func viewDidLoad() {
super.viewDidLoad()


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


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


self.navigationController?.interactivePopGestureRecognizer?.gesture.isEnabled = false
}


}

它适用于我的大多数视图控制器。

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

对于一些视图控制器,比如UIPageViewController,它并不是无效的。在UIPageViewController的pagecontentviewcontroller下面的代码为我工作。

override func viewDidLoad() {
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}
override func viewWillDisappear(_ animated: Bool) {
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
}

UIGestureRecognizerDelegate,

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
return false
}
return true
}

Swift 5、Swift 4.2可以使用下面的代码。

// disable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
// enable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
self.navigationController.pushViewController(VC, animated: Bool)

调用

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

setViewControllers替换堆栈上的所有VCs,而不是在顶部添加一个新的控制器。这意味着新的集合VC是根VC,用户不能返回。

当你只想在一个VC上禁用滑动,而在另一个VC上保持滑动时,这是最有效的。

如果你想让用户能够返回,而不是通过滑动,不要使用这个方法,因为它会禁用所有返回(因为没有VC可以返回)