繁体   English   中英

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

[英]How to disable back swipe gesture in UINavigationController on iOS 7

在 iOS 7 Apple 添加了新的默认导航行为。 您可以从屏幕的左边缘滑动到导航堆栈上的 go。 但在我的应用程序中,此行为与我的自定义左侧菜单冲突。 那么,是否可以在 UINavigationController 中禁用此新手势?

我找到了一个解决方案:

目标-C:

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

斯威夫特 3+:
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

我发现将手势设置为仅禁用并不总是有效。 它确实有效,但对我来说只有在我使用过 backgesture 之后才有效。 第二次它不会触发backgesture。

对我来说修复是委托手势并实现 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;
}

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

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

从 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;
}

我稍微改进了 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;
}

对于斯威夫特:

navigationController!.interactivePopGestureRecognizer!.enabled = false

请在根 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;
}

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

// disable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
// enable
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true

编辑

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

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

例如:

#import <SwipeBack/SwipeBack.h>

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

它可以通过CocoaPods安装。

pod 'SwipeBack', '~> 1.0'

我为缺乏解释而道歉。

它适用于 ios 10 及更高版本:

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

}

它不适用于 viewDidLoad() 方法。

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

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

这是 Swift 3 的方式

为我工作

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

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

[navigationController.interactivePopGestureRecognizer requireGestureRecognizerToFail: myPanGestureRecognizer];

其中 myPanGestureRecognizer 是您用来显示菜单的手势识别器。 这样,当您按下新的导航控制器时,Apple 的手势识别器不会被它们重新打开,并且您不需要依赖可能会在您的手机进入睡眠状态或负载过重时过早触发的黑客延迟。

把它留在这里是因为我知道下次需要它时我不会记住它,然后我会在这里找到问题的解决方案。

这适用于viewDidLoad:对于 iOS 8:

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

很多问题都可以在好的 ol' 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之后禁用向后滑动

对于Swift 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
}
self.navigationController.pushViewController(VC, animated: Bool)

称呼

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

setViewControllers 替换堆栈中的所有 VC,而不是在顶部添加新的 controller。 这意味着新设置的VC是根VC,用户不能go回来。

当您只想禁用单个 VC 上的滑动并为另一个 VC 保持向后滑动时,这是最有效的。

如果您希望用户能够返回 go,而不是通过滑动,请不要使用此方法,因为它会禁用所有返回(因为没有 VC 到 go 返回)

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM