ios 设置 leftBarButtonItem 后如何在 UINavigationController 中启用向后/向左滑动手势?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34942571/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 08:37:43  来源:igfitidea点击:

How to enable back/left swipe gesture in UINavigationController after setting leftBarButtonItem?

iosobjective-cuinavigationcontrolleruinavigationbaruinavigationitem

提问by Itachi

I got the opposite issue from here. By default in iOS7, back swipe gesture of UINavigationController's stack could pop the presented ViewController. Now I just uniformed all the self.navigationItem.leftBarButtonItemstyle for all the ViewControllers.

我从这里得到了相反的问题。默认情况下iOS7UINavigationController堆栈的向后滑动手势可以弹出呈现的ViewController. 现在我只是统一self.navigationItem.leftBarButtonItem了所有ViewControllers.

Here is the code:

这是代码:

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:LOADIMAGE(@"back_button") style:UIBarButtonItemStylePlain target:self action:@selector(popCurrentViewController)];

after that, the navigationController.interactivePopGestureRecognizeris disabled. How could I make the pop gesture enabled without removing the custom leftBarButtonItem?

之后,将navigationController.interactivePopGestureRecognizer被禁用。如何在不删除自定义的情况下启用弹出手势leftBarButtonItem

Thanks!

谢谢!

回答by Lumialxk

First set delegate in viewDidLoad:

首先在 viewDidLoad 中设置委托:

self.navigationController.interactivePopGestureRecognizer.delegate = self;

And then disable gesture when pushing:

然后在按下时禁用手势:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
    [super pushViewController:viewController animated:animated];
    self.interactivePopGestureRecognizer.enabled = NO;
}

And enable in viewDidDisappear:

并在 viewDidDisappear 中启用:

self.navigationController.interactivePopGestureRecognizer.enabled = YES;

Also, add UINavigationControllerDelegateto your view controller.

此外,添加UINavigationControllerDelegate到您的视图控制器。

回答by iwasrobbed

You need to handle two scenarios:

您需要处理两种情况:

  1. When you're pushing a new view onto the stack
  2. When you're showing the root view controller
  1. 当您将新视图推入堆栈时
  2. 当您显示根视图控制器时

If you just need a base class you can use, here's a Swift 3 version:

如果你只需要一个可以使用的基类,这里有一个 Swift 3 版本:

import UIKit

final class SwipeNavigationController: UINavigationController {

    // MARK: - Lifecycle

    override init(rootViewController: UIViewController) {
        super.init(rootViewController: rootViewController)
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

        delegate = self
    }

    required init?(coder aDecoder: NSCoder) { 
        super.init(coder: aDecoder) 

        delegate = self 
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // This needs to be in here, not in init
        interactivePopGestureRecognizer?.delegate = self
    }

    deinit {
        delegate = nil
        interactivePopGestureRecognizer?.delegate = nil
    }

    // MARK: - Overrides

    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        duringPushAnimation = true

        super.pushViewController(viewController, animated: animated)
    }

    // MARK: - Private Properties

    fileprivate var duringPushAnimation = false

}

// MARK: - UINavigationControllerDelegate

extension SwipeNavigationController: UINavigationControllerDelegate {

    func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
        guard let swipeNavigationController = navigationController as? SwipeNavigationController else { return }

        swipeNavigationController.duringPushAnimation = false
    }

}

// MARK: - UIGestureRecognizerDelegate

extension SwipeNavigationController: UIGestureRecognizerDelegate {

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard gestureRecognizer == interactivePopGestureRecognizer else {
            return true // default value
        }

        // Disable pop gesture in two situations:
        // 1) when the pop animation is in progress
        // 2) when user swipes quickly a couple of times and animations don't have time to be performed
        return viewControllers.count > 1 && duringPushAnimation == false
    }
}

If you end up needing to act as a UINavigationControllerDelegatein another class, you can write a delegate forwarder similar to this answer.

如果您最终需要UINavigationControllerDelegate在另一个类中充当 a ,您可以编写一个类似于此答案的委托转发器。

Adapted from source in Objective-C: https://github.com/fastred/AHKNavigationController

改编自 Objective-C 中的源代码:https: //github.com/fastred/AHKNavigationController

回答by hfossli

It works for me when I set the delegate

当我设置委托时它对我有用

self.navigationController.interactivePopGestureRecognizer.delegate = self;

and then implement

然后执行

Swift

迅速

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

Objective-C

目标-C

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}

回答by Yahya Tabba

it works for me Swift 3:

它适用于我Swift 3

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

and in ViewDidLoad:

在 ViewDidLoad 中:

    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true

回答by Mr. Bean

This is the best way to enable/ disable swipe to pop view controller in iOS 10, Swift 3:

这是在iOS 10, Swift 3 中启用/禁用滑动到弹出视图控制器的最佳方法:

For First Screen [ Where you want to Disable Swipe gesture ] :

对于第一个屏幕 [您要禁用滑动手势的位置]:

class SignUpViewController : UIViewController,UIGestureRecognizerDelegate {

//MARK: - View initializers
override func viewDidLoad() {
    super.viewDidLoad()
}

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

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

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func swipeToPop() {

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true;
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self;
}

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {

    if gestureRecognizer == self.navigationController?.interactivePopGestureRecognizer {
        return false
    }
    return true
} }

For middle screen [ Where you want to Enable Swipe gesture ] :

对于中间屏幕[您要启用滑动手势的位置]:

class FriendListViewController : UIViewController {

//MARK: - View initializers
override func viewDidLoad() {

    super.viewDidLoad()
    swipeToPop()
}

func swipeToPop() {

    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true;
    self.navigationController?.interactivePopGestureRecognizer?.delegate = nil;
} }

回答by Josh O'Connor

Swift 3:

斯威夫特 3:

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

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

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

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return (otherGestureRecognizer is UIScreenEdgePanGestureRecognizer)
}

回答by Axel Guilmin

Setting a custom back button disable the swipe back feature.

设置自定义后退按钮会禁用向后滑动功能。

The best thing to do to keep it is to subclass UINavigationViewControllerand set itself as the interactivePopGestureRecognizerdelegate; then you can return YES from gestureRecognizerShouldBeginto allow the swipe back.

保持它的最好办法是子类化UINavigationViewController并将自己设置为interactivePopGestureRecognizer委托;然后您可以返回 YESgestureRecognizerShouldBegin以允许向后滑动。

For example, this is done in AHKNavigationController

例如,这是在AHKNavigationController 中完成的

And a Swift version here: https://stackoverflow.com/a/43433530/308315

这里有一个 Swift 版本:https: //stackoverflow.com/a/43433530/308315

回答by Burcu Kutluay

I did not need to add gestureRecognizer functions for it. It was enough for me to add following code blocks at viewDidLoad:

我不需要为它添加gestureRecognizer 函数。我在 viewDidLoad 中添加以下代码块就足够了:

override func viewDidLoad() {
    super.viewDidLoad()
    self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
}

回答by Jonny

Thisanswer, but with storyboard support.

这个答案,但有故事板支持。

class SwipeNavigationController: UINavigationController {

    // MARK: - Lifecycle

    override init(rootViewController: UIViewController) {
        super.init(rootViewController: rootViewController)
    }

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        self.setup()
    }

    private func setup() {
        delegate = self
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // This needs to be in here, not in init
        interactivePopGestureRecognizer?.delegate = self
    }

    deinit {
        delegate = nil
        interactivePopGestureRecognizer?.delegate = nil
    }

    // MARK: - Overrides

    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        duringPushAnimation = true

        super.pushViewController(viewController, animated: animated)
    }

    // MARK: - Private Properties

    fileprivate var duringPushAnimation = false
}

回答by Andriy Gordiychuk

If you want this behaviour everywhere in your app and don't want to add anything to individual viewDidAppearetc. then you should create a subclass

如果您希望在您的应用程序中随处可见这种行为,并且不想向个人viewDidAppear等添加任何内容,那么您应该创建一个子类

class QFNavigationController:UINavigationController, UIGestureRecognizerDelegate, UINavigationControllerDelegate{
    override func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
        delegate = self
    }

    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        super.pushViewController(viewController, animated: animated)
        interactivePopGestureRecognizer?.isEnabled = false
    }

    func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
        interactivePopGestureRecognizer?.isEnabled = true
    }

    // IMPORTANT: without this if you attempt swipe on
    // first view controller you may be unable to push the next one
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }

}

Now, whenever you use QFNavigationControlleryou get the desired experience.

现在,无论何时使用,QFNavigationController您都会获得所需的体验。