UINavigationController Interactive Pop Gesture Not Working?

跟風遠走 提交于 2019-11-28 19:14:27

I have found that when using custom back buttons, the interactive pop gesture stops working (my take is that Apple cannot foresee how your custom back button will behave, so they disable the gesture).

To fix this, as other mentioned before, you can set the interactivePopGestureRecognizer.delegate property to nil.

In Swift, this can easily be done across your entire application by adding an extension for UINavigationController like this:

extension UINavigationController {

    override public func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = nil
    }

}

Updated answer

Seems like setting the delegate to nil causes the app UI to freeze in some scenarios (eg. when the user swipes left or right on the top view controller of the navigation stack).

Because gestureRecognizerShouldBegin delegate method cannot be handled in an extension, subclassing UINavigationController seems like the best solution:

class NavigationController: UINavigationController, UIGestureRecognizerDelegate {

    /// Custom back buttons disable the interactive pop animation
    /// To enable it back we set the recognizer to `self`
    override func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }

}

Eh, looks like I just had to set the gesture delegate and implement the following:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {

    return YES;

}
cromandini

Look at this response and comments. All you have to do is set your navigation controller's interactive pop gesture recognizer's delegate to nil:

self.navigationController.interactivePopGestureRecognizer.delegate = nil;

Setting it to a casted self to id<UIGestureRecognizerDelegate> also works because all methods in the protocol are optional, but I think setting the delegate to nil is more appropriate in this case.

You can put this line in the viewDidLoad method.

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
Vicky Dhas

The more worked out answer was both Aaron and lojals

First Customise the Navigation controller and then put this code in the class

In ViewDidload put this line:

self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;

And in class write this function

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

Maybe someone may find this helpful.

If you want to hide the navigation bar but use normal swipe gestures to go back and other navigation controller features, you should use: (navigationBar)

self.navigationController?.navigationBar.isHidden = true

If you want to disable navigation bar (hide navigation bar, disable swipe for back) but want to push viewcontroller you should use: (isNavigationBarHidden)

self.navigationController?.isNavigationBarHidden = true

Update 7-DEC-2018:

In case that your first controller use hidden navigation bar, but next childs use navigation bar, when you come back to base view controller you will see a black bar in transition in place of navigation bar. This will be fixed very easy if you use in first viewcontroller(father):

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationController?.setNavigationBarHidden(true, animated: animated)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.setNavigationBarHidden(false, animated: animated)
}

In Swift 4, I have a UITableView inside my view controller, I solved this issue with:

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

Generically add interactive pop gesture to the whole app.

XCODE: 9.0, Swift: 4.0

Preferably create UINavigationController in AppDelegate.swift

  1. Create a navigation controller
// I created a global variable, however not necessarily you will be doing this way
var nvc: UINavigationController!
  1. implement UIGestureRecognizerDelegate
class AppDelegate: UIResponder, UIApplicationDelegate, UIGestureRecognizerDelegate {
  1. Instantiat UINavigationController in application didFinishLaunchingWithOptions function
nvc=UINavigationController()

// For interactive pop gesture
nvc.navigationBar.isHidden=true
nvc?.interactivePopGestureRecognizer?.delegate=self
  1. Extra step, add controller to navigation controller in application didFinishLaunchingWithOptions function
window=UIWindow()
window?.rootViewController=nvc
window?.makeKeyAndVisible()

// BaseViewController is sample controller i created with xib
nvc.pushViewController(BaseViewController(), animated: true)
  1. Implement gusture recognizer, add below code to AppDelegate.swift
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }



Note: See other post in this section for the difference between

self.navigationController?.navigationBar.isHidden=true

And

self.navigationController?.isNavigationBarHidden = true

My answer is based on Eneko's answer but uses only an extensions on UINavigationController and works in Swift 5:

extension UINavigationController: UIGestureRecognizerDelegate {

    override open func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return viewControllers.count > 1
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!