Question

After reading a bunch of similar questions on SO I've found out that in order to use a custom back button view I should be setting the nav controller's nav bar's nav item's left button item to a custom view, but no matter what I do I'm getting stuck with the default. I've tried setting this both inside the view controller I want to navigate back from, as well as the one I'm navigating back to, to no avail. Any ideas what I might be doing wrong?

- (void)loadView{
    [super loadView];
     UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc]initWithCustomView:[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"back-btn"]]];
    self.navigationController.navigationItem.leftBarButtonItem = backButtonItem;
    self.navigationController.navigationItem.leftBarButtonItem.tintColor = [UIColor whiteColor];
    [self.navigationController setNavigationBarHidden:YES animated:YES];
}
Was it helpful?

Solution

The key thing you’re doing wrong is using the bar button item on the navigation controller instead of on your view controller. To quote Apple’s View Controller Catalog for iOS:

In a navigation interface, each content view controller in the navigation stack provides a navigation item as the value of its navigationItem property.

Emphasis mine; the content view controller is your custom view controller. Try this:

self.navigationItem.leftBarButtonItem = backButtonItem;

You need to do this in all your view controllers that should have the custom button, so I recommend creating your own base view controller class that subclasses UIViewController and implements custom back buttons, and use this base view controller as the parent of your other view controllers.

You’re hiding the navigation bar, which probably isn’t a good idea if you want it to show a custom back button.

By replacing the standard back button, you lose its tap behaviour. Use a UIButton in the bar button item’s custom view instead of a UIImageView.

Also, it would be more conventional to put this setup code in viewDidLoad rather than loadView.

So I would do something like this:

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [backButton setBackgroundImage:[UIImage imageNamed:@"back-btn"] forState:UIControlStateNormal];
    [backButton sizeToFit];
    [backButton addTarget:self action:@selector(popNavigationController:) forControlEvents:UIControlEventTouchUpInside];

    UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
    self.navigationItem.leftBarButtonItem = backButtonItem;
}

- (void)popNavigationController:(id)sender
{
    [[self navigationController] popViewControllerAnimated:YES];
}

Note that if you use a custom back button, the swipe-from-the-edge-of-the-screen-to-go-back gesture will not work. See this Stack Overflow question for a couple of potential solutions, but it’s fiddly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top