简体   繁体   中英

Is it possible to change the navigation bar title outside of viewDidLoad/viewWillAppear?

I'm trying to change the navigation bar title with this statement:

[[self navigationItem] setTitle:myTitle];

It works fine in viewDidLoad and viewWillAppear, but it doesn't work anywhere else. Is what I am trying to do possible? It's a view controller I'm working with.

There is a very simple way to change the title for the current view controller.

self.title = @"New Title";

Calling this on a view controller that is in a navigation controller will result in the title shown in the navigation bar being updated with the new title.

This can be called at any time while the view controller is displayed.

There is no need to dig into the view controller's navigationItem for setting the title.

I know this is old, but I wanted to answer this for future users. I think the main issue that most answers don't cover is that it is important to set the title from the main thread, otherwise there are a handful of cases where it won't get set immediately. For Swift 3.0 you can use code like this:

 DispatchQueue.main.async {
        self.title = "Example string"
 }

It is important to do all UI updates from the main thread. I'm not sure if the original user was setting the title via an asynchronous closure, but this should help anyone who is having difficulties.

It's actually the view controller's title property that the navigationItem will use. The answer above is the simplest and correct way to change the title in the navigation bar.

If you need to customize your navigation bar, the way you do this is to override it in your UIViewController subclass, NOT change it in viewDidAppear: or any other viewWill/Did methods

- (UINavigationItem*)navigationItem
{
  UINavigationItem *navigationItem = [super navigationItem];

  // customize it further than the default

  return navigationItem;
}

In addition, you can have changes in your title update a custom titleView using KVO. You listen for changes in the UIViewController's title property and update the titleView property of your navigationItem. Check this out:

static void *kObjectStateObservingContext = &kObjectStateObservingContext;  // outside your @implementation bit

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // other init stuff here...

        [self addObserver: self forKeyPath:@"title" options:NSKeyValueObservingOptionNew context: kObjectStateObservingContext];
    }
    return self;
}

Don't forget to remove the observer:

- (void)dealloc
{
    [self removeObserver: self forKeyPath:@"title"];
}

And now we revisit the navigationItem again, where you can create a custom UILabel that will update whenever we change the title, and after that we have to provide a handler implementation for when the title does change:

- (UINavigationItem*)navigationItem
{
    UINavigationItem *navigationItem = [super navigationItem];

    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(roundf((320 - 230)/2), 0, 230, 44)];
    titleLabel.font = [UIFont systemFontOfSize: 18];
    titleLabel.textColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"topnav-background-text-gradient.png"]];  // you can even draw the font with a gradient!
    titleLabel.shadowColor = [UIColor colorWithWhite: 1.0 alpha:0.59];
    titleLabel.shadowOffset = CGSizeMake(0, 1.0);
    titleLabel.text = self.title;
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.textAlignment = UITextAlignmentCenter;

    navigationItem.titleView = titleLabel;

    return navigationItem;
}

And finally, what to do when self.title actually changes:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ( context == kObjectStateObservingContext ) {
        // here we update the text of the titleView
        if ([self.navigationItem.titleView isKindOfClass:[UILabel class]]) {
            [(UILabel*)self.navigationItem.titleView setText: self.title];
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

And there you go! Obviously a bit more code than you might have thought, so if you're not currently, I recommend to anyone building iOS Apps that you always create a base class view controller for your application, (MyBaseViewController : UIViewController) then subclass that for any other view controllers in your app.

You can set up the the title in viewDidLoad , because the view is not yet visible but instaciated. Same story for viewWillAppear . After the UIElement is visible, you cant change the title without a redraw .

@reid55 you can set navigation title in below method also:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
  self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
  if (self) {
   [[self navigationItem] setTitle:myTitle];
}
return self;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM