'Disable swipe back gesture in Swift

Been looking around on here for a while but can't seem to find a working solution.

I'm trying to disable the swipe to go back to previous view gesture, in Swift.

I've tried a variety of solutions including:

self.navigationController?.interactivePopGestureRecognizer.enabled = false

and

self.navigationController.interactivePopGestureRecognizer.delegate = self

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer!) -> Bool {
    return false
}

Is there a new method of doing this or some other method that works?



Solution 1:[1]

You could disable it but that would not be to recommended as most iOS users go back by swiping and less by pressing the back button. If you want to disable it it would be more reasonable to use a modal segue instead of a push segue which is not that big of a transfer. If you really want to get rid of the swipe to go back function I would just disable the back button and have a done button on the top right of the screen.

self.navigationController?.navigationItem.backBarButtonItem?.isEnabled = false;

Solution 2:[2]

The following is an easy approach to disabling & re-enabling the swipe back.

Swift 3.x & up

In a viewDidLoad/willAppear/didAppear method add:

navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Just keep in mind that if you do it with viewDidLoad, then the next time you open the view, it may not be set depending upon whether or not it remains in your stack.

Unless you want it to remain off, you will need to turn it back on when the view is closed via either willMove(toParentViewController:) or willDisappear. Your navigationController will be nil at viewDidDisappear, so that is too late.

navigationController?.interactivePopGestureRecognizer?.isEnabled = true

A special note on SplitViewControllers:

As pointed out by CompC in the comments, you will need to call the second navigation controller to apply it to a detail view as such:

navigationController?.navigationController?.interactivePopGe??stureRecognizer?.isE??nabled = false

Swift 2.2 & Objective-C

Swift versions 2.x & below:

navigationController?.interactivePopGestureRecognizer?.enabled

Objective-C:

self.navigationController.interactivePopGestureRecognizer.enabled

Solution 3:[3]

I was able to do this by returning false in gestureRecognizerShouldBegin

class ViewController2: UIViewController, UIGestureRecognizerDelegate {
...
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    self.navigationController?.interactivePopGestureRecognizer.delegate = self
}

func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
    return false
}

Solution 4:[4]

Add this line before pushing view controller to navigation controller

self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false

Solution 5:[5]

Nothing wrong with either answer from Hari or Stefan but this is more succinct. Just put it in viewDidLoad and you're done.

if navigationController!.respondsToSelector(Selector("interactivePopGestureRecognizer")) {
    navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer)
}

EDIT:

One small caveat is that if the Navigation Controller was opened by another view and the Navigation Controller is closed then you'll get an EXC_BAD_ACCESS error. To fix it you have to save the original UIGestureRecognizer and put it back when you exit the view.

Declare:

private var popGesture: UIGestureRecognizer?

Immediately before removing the gesture:

popGesture = navigationController!.interactivePopGestureRecognizer

Then when closing the view:

If popGesture != nil {
    navigationController!.view.addGestureRecognizer(popGesture!)
}

Solution 6:[6]

RowanPD's logic for Swift 4

private var popGesture: UIGestureRecognizer?

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

    if navigationController!.responds(to: #selector(getter: UINavigationController.interactivePopGestureRecognizer)) {
        self.popGesture = navigationController!.interactivePopGestureRecognizer
        self.navigationController!.view.removeGestureRecognizer(navigationController!.interactivePopGestureRecognizer!)
    }

}

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

    if let gesture = self.popGesture {
        self.navigationController!.view.addGestureRecognizer(gesture)
    }

}

Solution 7:[7]

Instead of

self.navigationController.pushViewController(VC, animated: Bool)

call

self.navigationController.setViewContollers([VC], animated: Bool)

setViewControllers replaces the all the VCs on the stack, instead of adding a new controller on top. This means that the new set VC is the root VC, and the user cannot go back.

This is most effective when you only want to disable the swipe on a single VC, and keep the swipe-to-back for the other VC.

If you want users to be able to go back, just not through swiping, do not use this method as it will disable all backs (as there is no VC to go back to).

Solution 8:[8]

for objective -c

-(void)viewWillAppear:(BOOL)animated{
  [super viewWillAppear:true];

  self.navigationController.interactivePopGestureRecognizer.enabled = NO;

}

Solution 9:[9]

I generally make sure that swipe back is enabled in as many places as possible, even adding a custom gesture recognizer to add it to modal screens. However for an authentication and download process in my app I start the process with a modal navigation controller and then push the view for each next step. However, once it's completed I want to prevent them from backing up into the authentication screens.

For this scenario I've been using:

navigationController?.interactivePopGestureRecognizer?.isEnabled = false
navigationItem.hidesBackButton = true

in viewWillAppear() on the final screen. You can undo these in viewWillDisappear() if you're pushing another view and need them there.

Solution 10:[10]

This is something you missed if it doesn't work after you tried all.

  1. Add navigationController?.interactivePopGestureRecognizer?.isEnabled = false to your viewWillAppear(animated:) method.
  2. if it doesn't work, remove navigation delegate from the view controller. Check again if your view controller is confirming UINavigationControllerDelegate, UIGestureRecognizerDelegate protocols. if so, just remove it.

Solution 11:[11]

Come here a little bit late. In my case self.navigationController?.navigationItem.backBarButtonItem?.isEnabled = false; not working. So I do this: you can present view controller instead of push view controller. This way the swipe back gesture will not apply to the view controller.

navigationController?.present(vc, animated: true)

You could use dismiss for your custom back button

self.dismiss(animated: true)

Note: You could set VC modal presentation style before present it to make sure it's full screen.

vc.modalPresentationStyle = .fullScreen

Hope this help.

Solution 12:[12]

If requirement is to show side menu on some of the screens then add AddScreenEdgePanGesture on this specific view instead of navigationController view

replace it

SideMenuManager.default.menuAddScreenEdgePanGesturesToPresent(toView: self.navigationController?.view)

with this

SideMenuManager.default.menuAddScreenEdgePanGesturesToPresent(toView: self.view)

Solution 13:[13]

If you don't care about system back button appearance (for example, if you're using custom back button or navigation bar is hidden at all), it might help you:

navigationItem.hidesBackButton = true

It hides back button and disables swipe back gesture.

Solution 14:[14]

Only complete removal of the gesture recognizer worked for me (from the presenting view controller).

if let navigationController = parent.navigationController,
   let interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer {
    navigationController.view.removeGestureRecognizer(interactivePopGestureRecognizer)
}

Solution 15:[15]

Don't Use this if you don't want to come back, or you set the new rootViewController.

self.navigationController.pushViewController(VC, animated: Bool)

Use this

self.navigationController.setViewContollers([VC], animated: Bool)

setViewControllers Remove all the View Controllers on the stack then the user cannot go back. it will disable all backs