30

I have a UITableView and it has a nav bar(got from UINavigationViewController), it's able to go back by sliding back using a finger.

I tried to hide the nav bar but keep the slide-back ability, code:

- (void)viewWillAppear:(BOOL)animated {
    [[self navigationController] setNavigationBarHidden:YES animated:YES];
}

This successfully hid the nav bar, however, I can no longer slide back to the last screen either.

Is there any way to hide the nav bar but keep the slide-back ability?

Ascendant
  • 2,430
  • 3
  • 26
  • 34

9 Answers9

64

Tested with Swift 2 the solution of @gabbler, if you use

self.navigationController?.navigationBar.hidden = true

Swift 3.0

self.navigationController?.navigationBar.isHidden = true

instead of

self.navigationController?.navigationBarHidden = true

the swipe back gesture works like a charm!

Mohamed Jaleel Nazir
  • 5,776
  • 3
  • 34
  • 48
Ber.to
  • 1,064
  • 1
  • 10
  • 15
  • For some amazingly werid and beautiful reason this actually works. Might it be a bug in UIKit? – Entalpi Jun 29 '16 at 15:23
  • 2
    Note that animating this to be **system-smooth** in `viewWillAppear:` and `viewWillDisappear:` to disable a `UINavigationBar` in a particular `UIViewController` inside a `UINavigationController` can be a really good challenge, especially when doing `viewWillDisappear:`. For that particular case, we use `setNavigationBarHidden:animated:` but this also disables the `interactivePopGestureRecognizer`. In my particular case, I don't do what this answer says because it's hard and pretty much buggy to animate this property. – Alejandro Iván Feb 07 '17 at 15:58
  • `self.navigationController?.navigationBar.isHidden = true` does not hide the nav bar in iOS 11/Swift 4.x; only `self.navigationController?.navigationBarHidden = true` does. – Evan R Mar 27 '18 at 12:37
  • @EvanR, on my device and simulator (latest iOS - 11.3) works fine. – Vadim May 16 '18 at 14:35
  • 1
    I can confirm that it's still working on iOS 11.4 and Swift 4.x. – atereshkov Jul 23 '18 at 11:49
26

Found the solution:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    // hide nav bar
    [[self navigationController] setNavigationBarHidden:YES animated:YES];

    // enable slide-back
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        self.navigationController.interactivePopGestureRecognizer.delegate = self;
    }
}


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

And in .h file, conform to UIGestureRecognizerDelegate

atulkhatri
  • 10,896
  • 3
  • 53
  • 89
Ascendant
  • 2,430
  • 3
  • 26
  • 34
  • 1
    It is working fine! Instead of setting **setNavigationBarHidden:YES**, in a Embed In > Navigation Controller then select _UINavigationController_ and uncheck **Shows Navigation Bar**. By unchecking that, hiding navigation bar code can be removed. – Antony Raphel Dec 28 '16 at 12:47
7

Use

self.navigationController.navigationBar.hidden = YES;

or add this line in viewWillAppear:

self.navigationController.interactivePopGestureRecognizer.delegate = self;

It seems the interaction is not effective, adding this line and make the view controller conforms to the UIGestureRecognizerDelegate protocol will make it work.

gabbler
  • 13,626
  • 4
  • 32
  • 44
3

Make sure to include:

self.navigationController.navigationBar.hidden = YES;

And:

self.navigationController.interactivePopGestureRecognizer.delegate = self;

And:

if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
        self.navigationController.interactivePopGestureRecognizer.enabled = YES;
    }

It should appear like this:

- (void)viewWillAppear:(BOOL)animated {

    self.navigationController.navigationBar.hidden = YES;
    self.navigationController.interactivePopGestureRecognizer.delegate = self;
    if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
            self.navigationController.interactivePopGestureRecognizer.enabled = YES;
        }
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    return YES;
}
Wyetro
  • 8,439
  • 9
  • 46
  • 64
  • Thanks for the edit, it assigns the delegate to itself, but it doesn't implement the gestureRecognizerShouldBegin method. I've added the solution that works for me. Thank you for your effort, I appreciate it. – Ascendant Oct 13 '14 at 03:26
  • @ZinanXing, haha I added that to my code and then I saw where you said you found a solution... – Wyetro Oct 13 '14 at 03:48
3

Swift 4.x and iOS 11.4.

The @gabbler solution is still working. Idk, looks like this is a UIKit bug, but..

Just use:

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

    self.navigationController?.navigationBar.isHidden = true
}

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

    self.navigationController?.navigationBar.isHidden = false
}
atereshkov
  • 4,311
  • 1
  • 38
  • 49
2

Zinan Xings solution in Swift 4.2 (Please give him upvote!):

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

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

    self.navigationController?.setNavigationBarHidden(true, animated: true)
    self.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
    self.navigationController?.interactivePopGestureRecognizer?.delegate = self
}
Sean Stayns
  • 4,082
  • 5
  • 25
  • 35
1

for Xamarin Forms i was Struggle with this so first don't NavigationRenderer you'll get NavigationController null instead use PageRenderer:

[assembly: Xamarin.Forms.ExportRenderer(typeof(ContentPage), typeof(ContentPageRenderer))]
namespace sample
{
    class ContentPageRenderer : PageRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewDidAppear(animated);

            var navctrl = this.ViewController.NavigationController;
            navctrl.InteractivePopGestureRecognizer.Delegate = new UIGestureRecognizerDelegate();
            navctrl.InteractivePopGestureRecognizer.Enabled = true;

        }
    }
}
Abdullah Tahan
  • 1,963
  • 17
  • 28
1

Here is a working code for Swift 5:

private func setupNavController() {
            
    navigationController?.setNavigationBarHidden(true, animated: true)     
    self.navigationController?.interactivePopGestureRecognizer?.delegate = nil
    if let interactivePopGestureRecognizer = navigationController?.interactivePopGestureRecognizer {
        self.tableView.panGestureRecognizer.require(toFail: interactivePopGestureRecognizer)
    }
}

I have a UIViewController which contains a UITableView inside. This code helps you keep the smooth transition when you swipe back or press the back button. Call this function in viewWillAppear.

Starsky
  • 1,829
  • 18
  • 25
0

If hiding the the navigation bar did't help, try changing the rect of the navigation bar and see?

navBarBgFrame.origin.y = - navBarBgFrame.size.height;

Prabhu.Somasundaram
  • 1,380
  • 10
  • 13