web-dev-qa-db-ja.com

leftBarButtonItemを設定した後、UINavigationControllerで戻る/左スワイプジェスチャーを有効にする方法

here から逆の問題を取得しました。 iOS7のデフォルトでは、UINavigationControllerのスタックのバックスワイプジェスチャは、提示されたViewControllerをポップする可能性があります。これで、すべてのViewControllersのすべてのself.navigationItem.leftBarButtonItemスタイルを統一しました。

コードは次のとおりです。

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

その後、navigationController.interactivePopGestureRecognizerは無効になります。カスタムleftBarButtonItemを削除せずに、ポップジェスチャを有効にするにはどうすればよいですか?

ありがとう!

58
Itachi

ViewDidLoadで最初にデリゲートを設定します。

self.navigationController.interactivePopGestureRecognizer.delegate = self;

そして、プッシュ時のジェスチャーを無効にします:

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

そして、viewDidDisappearで有効にします。

self.navigationController.interactivePopGestureRecognizer.enabled = YES;

また、UINavigationControllerDelegateをView Controllerに追加します。

63
Lumialxk

次の2つのシナリオを処理する必要があります。

  1. 新しいビューをスタックにプッシュしているとき
  2. ルートView Controllerを表示しているとき

使用できる基本クラスだけが必要な場合は、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
    }
}

別のクラスでUINavigationControllerDelegateとして動作する必要がある場合、デリゲートフォワーダー この回答と同様 を記述できます。

Objective-Cのソースから適応: https://github.com/fastred/AHKNavigationController

47
iwasrobbed

デリゲートを設定するとうまくいきます

self.navigationController.interactivePopGestureRecognizer.delegate = self;

そして実装

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

それは私のために働くSwift

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

およびViewDidLoadで:

    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
44
Yahya Tabba

これは、iOS 10、Swift 3 =:

最初の画面の場合[スワイプジェスチャを無効にする場所]:

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

中間画面[スワイプジェスチャを有効にする場所]:

class FriendListViewController : UIViewController {

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

    super.viewDidLoad()
    swipeToPop()
}

func swipeToPop() {

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

カスタムバックボタンを設定すると、スワイプバック機能が無効になります。

これを維持するための最善の方法は、UINavigationViewControllerをサブクラス化し、それ自体をinteractivePopGestureRecognizerデリゲートとして設定することです。その後、gestureRecognizerShouldBeginからYESを返して、スワイプバックを許可できます。

たとえば、これは AHKNavigationController で行われます

ここにSwiftバージョンがあります: https://stackoverflow.com/a/43433530/308315

3
Axel Guilmin

スウィフト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)
}
3
Josh O'Connor

これ 答えですが、ストーリーボードをサポートしています。

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
}
1
Jonny