Dulguun Otgon
Dulguun Otgon

Reputation: 1949

How can I change UINavigationController's rightBarButtonItem globally?

I'm trying to change navigation bar's right item globally. So I created parent class like this:

@implementation ParentViewController
...
- (void)loadView {
    [super loadView];

    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"send"]];
    self.navigationController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:sendImageView];

}
...
@end

And I have two ViewController classes named A and B that inherits from ParentViewController. Both of them has

- (void)loadView {
     [super loadView];
}

First instance of A comes out and performs

    B *vc = [[B alloc] init];
    [self.navigationController pushViewController:vc animated:YES];

The problem is that right bar button item appears only on A but not on B. I thought parent class's loadView getting called will do the trick but is not. How do I change that button globally?

I'm not using xib. So loadView always gets called.

Upvotes: 0

Views: 1406

Answers (3)

etipton
etipton

Reputation: 164

I recently wrote a blog post about this issue: http://www.codebestowed.com/ios-shared-barbuttonitems/

The basic idea is to subclass UINavigationController, give it a BarButtonItem property (self.myButton in the code below) and add code similar to:

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.delegate = self;
}

- (void)navigationController:(UINavigationController *)navigationController
    willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (!viewController.navigationItem.rightBarButtonItem) {
        viewController.navigationItem.rightBarButtonItem = self.myButton;
    }
}

For those interested, the blog post details how you can set this up further in InterfaceBuilder, which requires a bit of a hack (too much to go into in this answer).

Upvotes: 0

Dulguun Otgon
Dulguun Otgon

Reputation: 1949

I think I have found some way to solve it. It changes right item as plain image and sets left item as back button with the title of "Back".

@implementation ParentViewController

- (void)loadView {
    [super loadView];
    UIImageView *sendImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"send"]];
    sendImageView.frame = CGRectMake(0, 0, 44, 44);
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:sendImageView];

    //don't need the original back button
    self.navigationItem.hidesBackButton = YES;
    self.navigationItem.leftBarButtonItem = nil;
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(back)];
    [self.navigationItem.leftBarButtonItem configureFlatButtonWithColor:[UIColor whiteColor] highlightedColor:[UIColor lightGrayColor] cornerRadius:5];
    self.navigationItem.leftBarButtonItem.title = @"Back";
    [self.navigationItem.leftBarButtonItem
        setTitleTextAttributes:@{
            UITextAttributeTextColor: [UIColor colorFromHexCode:@"53a4db"],
     UITextAttributeTextShadowColor: [UIColor clearColor],
     UITextAttributeFont: [UIFont fontWithName:@"ChalkboardSE-Bold" size:15]
     } forState:UIControlStateNormal];
}

-(void)back {
    [self.navigationController popToRootViewControllerAnimated:YES];
}

@end

So if child class don't need to have back button it can self.navigationItem.leftBarButtonItem = nil;

Upvotes: 0

Wain
Wain

Reputation: 119031

loadView won't be called if the view controller has an associated XIB as that will be used to load the view.

You might want to consider acting as the delegate of UINavigationController to handle this stuff and implementing navigationController:willShowViewController:animated:. You can then directly interrogate the new viewController to decide if you should do anything and, if required, you can change its navigationItem.

Upvotes: 1

Related Questions