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

前端 未结 14 856
遥遥无期
遥遥无期 2020-11-28 22:48

I got the opposite issue from here. By default in iOS7, back swipe gesture of UINavigationController\'s stack could pop the presented ViewCon

14条回答
  •  有刺的猬
    2020-11-28 23:24

    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

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

    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 UINavigationControllerDelegate in another class, you can write a delegate forwarder similar to this answer.

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

提交回复
热议问题