No Swipe Back when hiding Navigation Bar in UINavigationController No Swipe Back when hiding Navigation Bar in UINavigationController ios ios

No Swipe Back when hiding Navigation Bar in UINavigationController


A hack that is working is to set the interactivePopGestureRecognizer's delegate of the UINavigationController to nil like this:

[self.navigationController.interactivePopGestureRecognizer setDelegate:nil];

But in some situations it could create strange effects.


Problems with Other Methods

Setting the interactivePopGestureRecognizer.delegate = nil has unintended side-effects.

Setting navigationController?.navigationBar.hidden = true does work, but does not allow your change in navigation bar to be hidden.

Lastly, it's generally better practice to create a model object that is the UIGestureRecognizerDelegate for your navigation controller. Setting it to a controller in the UINavigationController stack is what is causing the EXC_BAD_ACCESS errors.

Full Solution

First, add this class to your project:

class InteractivePopRecognizer: NSObject, UIGestureRecognizerDelegate {    var navigationController: UINavigationController    init(controller: UINavigationController) {        self.navigationController = controller    }    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {        return navigationController.viewControllers.count > 1    }    // This is necessary because without it, subviews of your top controller can    // cancel out your gesture recognizer on the edge.    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {        return true    }}

Then, set your navigation controller's interactivePopGestureRecognizer.delegate to an instance of your new InteractivePopRecognizer class.

var popRecognizer: InteractivePopRecognizer?override func viewDidLoad() {    super.viewDidLoad()    setInteractiveRecognizer()}private func setInteractiveRecognizer() {    guard let controller = navigationController else { return }    popRecognizer = InteractivePopRecognizer(controller: controller)    controller.interactivePopGestureRecognizer?.delegate = popRecognizer}

Enjoy a hidden navigation bar with no side effects, that works even if your top controller has table, collection, or scroll view subviews.


In my case, to prevent strange effects

Root view controller

override func viewDidLoad() {    super.viewDidLoad()    // Enable swipe back when no navigation bar    navigationController?.interactivePopGestureRecognizer?.delegate = self}// UIGestureRecognizerDelegatefunc gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {    if let navVc = navigationController {      return navVc.viewControllers.count > 1    }    return false}