How to show back button on the RootViewController of the UINavigationController?
Asked Answered
G

6

18

Here is my code. I want to put a back button on the opening rootviewController.

- (void)selectSurah:(id)sender {

    SurahTableViewController * surahTableViewController = [[SurahTableViewController alloc] initWithNibName:@"SurahTableViewController" bundle:nil];
    surahTableViewController.navigationItem.title=@"Surah";

    surahTableViewController.navigationItem.backBarButtonItem.title=@"Back";

    UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:surahTableViewController];

    [self presentModalViewController:aNavigationController animated:YES];   
}
Gainer answered 1/7, 2012 at 15:21 Comment(1)
The answer is obvious. go back where the presentModalViewController is called. See @Flex_Addicted answer below.Gainer
S
10

I don't believe it's possible to pop the root view controller off the navigation stack, but you can fake it with a UIButton added as the custom view of a UIBarButtonItem:

UIButton *b = [[UIButton alloc]initWithButtonType:UIButtonTypeCustom];
[b setImage:[UIImage imageNamed:@"BackImage.png"] forState:UIControlStateNormal];
[b addTarget:self action:@selector(back:) forControlEvents:UIControlEventTouchUpInside];
self.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:b];

A suitable PSD of iOS UI elements can be found here.

Strychnic answered 1/7, 2012 at 15:50 Comment(1)
Shorter way to achieve this will be - ` self.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"BackImage.png"] style:UIBarButtonItemStylePlain target:self action:@selector(showPopup:)] `Aphyllous
R
6

Faizan,

Helium3 comment makes sense.

I suppose that your button is needed to dismiss the controller presented modally, is it true? Correct if I'm wrong.

If so, you could just create a new UIBarButtonItem and set is a left (or right) button for the UINavigationController navigationItem. To not break encapsulation create it in the viewDidLoad method for your SurahTableViewController controller.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // make attention to memory leak if you don't use ARC!!!
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Close"
           style:UIBarButtonItemStyleBordered
             target:self
             action:@selector(close:)];
}

-(void)close:(id)sender
{
    // to dismiss use dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
    // dismissModalViewControllerAnimated: is deprecated

    [self dismissViewControllerAnimated:YES completion:^{ NSLog(@"controller dismissed"); }];
}
Recriminate answered 1/7, 2012 at 15:54 Comment(2)
Sorry for resurrecting the dead (thread), but just a note: you should add the button to the UIViewController being presented in the UINavigationController, not to the UINavigationController itself! This had me waste an hour or so :(Caulescent
@MadD Sorry for the delay. What do you mean? The button is attached to the navigation bar. Why does it not work for you? Thanks in advance.Recriminate
J
4

Since the SurahTableViewController is a root view controller in a navigation controller you can't go back to the root because you're already there. Since you've presented it modally from something else, you need to put a button on the nav bar that has an IBAction which calls:

[self dismissModalViewControllerAnimated:YES];
Jennine answered 1/7, 2012 at 15:51 Comment(0)
C
3

Appearance and behavior of a back button in a UINavigationController relies on interaction between a stack of UINavigationControllers. Putting a back button on the first controller breaks this convention, there's nothing to go back to, which is why your code isn't working.

You'll need to manually add UIBarButtonItem to the title bar code like:

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(back:)];

If you truly want it to look like a back button, you'll need to manually create the UIBarButtonItem with an image that mirrors the back button.

Another suggestion though, as it looks like you are attempting to use a back button to dismiss a modal view controller, I'd stick with something more conventional like a "Close" or "Done" button to close the modal view controller. A back button is really more appropriate for navigating a stack of UINavigationControllers.

Clodhopper answered 1/7, 2012 at 15:49 Comment(0)
N
0

Here's the answer I think everyone was looking for.

Simply provide an empty UIViewController as the rootViewController of your UINavigationController subclass in a custom initializer. Then push your actual rootViewController without animation before presenting:

init(backButtonRootViewController: UIViewController) {
    super.init(rootViewController: UIViewController())
    
    interactivePopGestureRecognizer?.isEnabled = false
    pushViewController(backButtonRootViewController, animated: false)
}

You'll also want to disable the interactivePopGestureRecognizer to prevent the user from swiping back to the empty rootViewController.

Then in extend your subclass to implement the shouldPop method of UINavigationBarDelegate and dismiss the navigation controller when the back button is pressed on the rootViewController:

func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
    
    if children.count >= 2 && children[1] == topViewController {
        presentingViewController?.dismiss(animated: true, completion: nil)
        return false
    } else {
        return true
    }
}

Works like a charm!

Nesline answered 14/10, 2021 at 15:1 Comment(0)
H
0

For Swift, try something like:

override func viewDidLoad() {
    super.viewDidLoad();
    self.navigationItem.hidesBackButton = true;
    let backButton = UIBarButtonItem(
        image: UIImage(named: "my_back_asset"), style: .plain,
        target: self, action: #selector(self.onBack));
    self.navigationItem.leftBarButtonItem = backButton;
}

@objc private func onBack() {
    let controller = self.navigationController?.popViewController(animated: true);
    if controller == nil {
        // Handle pressing back when on root here.
    }
}

Note to change "my_back_asset" to your own back-button image.

Huberthuberto answered 11/12, 2021 at 20:7 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.