UIViewController Title attribute in Storyboard - ios

I am setting the title field of a UIViewController via Interface Builder/Storyboard:
This view controller is nested in a UINavigationController which in turn is nested within a UITabBarController. When I run the app, I my navigation item has no title, neither does the tab bar item.
If I explicitly set the view controller's navigation item's title, and also it's tab bar item's title in interface builder, then it works just fine.
I am wondering:
a)If I am not using Storyboard but just regular xibs, setting the title of a view controller implicitly sets the navigation items' title as well as the tab bar item's title. But it's not the same storyboard. Is this the intended behaviour?
b) What is then the purpose of the view controller's title (in Storyboard)? it seems to have no effect.
Thanks!

You can set the title of the UINavigationBar in Storyboard by double clicking the actual navigationBar and typing in a title right there. This only sets the title for the UINavigationBar.
Setting the title in code offers some different possibilities.
self.title = #"Your title"; will set the title of a navigationBar and also cause the title to cascade down to a UITabBarItem, if present.
self.navigationItem.title = #"Your title"; will only set the title of the navigationBar, assuming a UINavigationController is present, and NOT affect a UITabBarItem.
self.navigationController.title = #"Your title"; will set the title of a UITabBarItem but NOT the UINavigationBar.

Step 1
If you're looking at a Xib in Xcode's Interface Builder, take a look in the "Document Outline" panel (second panel from the left). Expand the view controller you're working with until you find an icon labelled: Navigation Item.
Step 2
If you then highlight the Navigation Item and open up the Utilities panel (the farthest on the right), and click the Attributes Inspector, you'll see where you can set the title of the view controller. This is the way to do it in Interface Builder, rather than doing it through code.

I ran into this issue this morning. Here are the stabs I took and the final workaround.
This correctly logs the child view controller's title as set in the storyboard, but has no effect on what's being presented:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Title: %#", self.title);
}
This has no effect; the title still doesn't show (probably doing an "if (![_title isEqualToString:title]){}" user the hood:
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = [self.title copy];
}
This causes the title to be set correctly:
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *title = self.title;
self.title = nil;
self.title = title;
}
My guess is that the UINavigationController is pulling the title for the view being presented before it has been loaded from the storyboard, but then doesn't start listening for changes until after the property has been set. I don't use storyboards or nibs very often, however, so it's quite possible there's a magic checkbox for this hidden somewhere that I've missed.
In any case, it looks like you can either do the self.navigationItem.title = self.title dance, or the above, as a workaround and still maintain your titles in IB.
Apples docs for this are kinda clear:
The navigation controller updates the middle of the navigation bar as
follows:
If the new top-level view controller has a custom title view, the navigation bar displays that view in place of the default title view.
To specify a custom title view, set the titleView property of the view
controller’s navigation item.
If no custom title view is set, the navigation bar displays a label containing the view controller’s default title. The string for this
label is usually obtained from the title property of the view
controller itself. If you want to display a different title than the
one associated with the view controller, set the title property of the
view controller’s navigation item instead.
Emphasis mine.

I just ran into the same problem. I don't understand why it's not working... It might be on purpose or just be a bug.
To change the title in interface builder, you can click on the navigation item directly and change the title there:

Everything else on this page failed. For now, this worked, in code, in viewDidLoad:
NSString* text = #"My page title";
UIFont* font = [UIFont systemFontOfSize:20.0];
const CGSize SIZE = [text sizeWithAttributes:#{NSFontAttributeName:font}];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, SIZE.width, SIZE.height)];
label.text = text;
label.textColor = UIColor.blackColor;
self.navigationItem.titleView = label;

If you have UINavigationItem present, then you must use the navigation item title in the storyboard. If you don't have a navigation item for a view controller, then the UINavigationController will use the view controller's title property.
Example :
In your storyboard, if you have a navigation item the navigation controller doesn't need to read the view controller's title. Even if the title field is empty for this navigation item.
Remove the navigation item (if you can, you won't be able to do it for the root view controller but you will for the others) and your title will be correctly loaded

I think it works as designed although we expect another behaviour. If you print the title property in - (void)viewDidLoad it will be the same value that you set in story board so I see no reason of this not working unless Apple's choice.

a) If I am not using Storyboard but just regular xibs, setting the title of a view controller implicitly sets the navigation items' title as well as the tab bar item's title. But it's not the same storyboard. Is this the intended behavior?
I believe this is the intended behavior. I think that the purpose of the title attribute of a view controller is more of a property that can be used at the developer's discretion perhaps for distinguishing between controllers.
Another reason for this change I think is that your navigation item's title may need to be different than the tab bar title, since the tab bar title cannot be nearly as long as the navigation title.
b) What is then the purpose of the view controller's title (in Storyboard)? it seems to have no effect.
I think I mentioned this in my first paragraph. I think that the title attribute of a controller is a property that the developer can use perhaps for distinguishing between controllers.

I tried all of the above methods, even tried manually adding a navigation bar but to no avail.
So this is what worked for me.
Remove any navigation bar item you manually added to the view controller and add this to your viewDidLoad method
self.navigationController.navigationBar.topItem.title = #"My Title";
or
self.navigationController.topViewController.title = #"My Title";

In my case I solve with this:
[self.tabBarController.navigationItem setTitle:#"My Title"];

Related

How to set Title Bar for multiple tabed view?

I want to add title named News at the top of this view. I tried self.navigationItem.title = #"News" and self.navigationItem.titleView = #"News" but nothing happened. How can i set it ?
I think You have to try this one. In the viewController ViewDidLoad method.
self.title=#"Home";
You just cant add a title directly at top of the view, either you need to take a uilabel in which you will write your title or you have to embed your each view controller with navigation controller

iOS - Replace SegmentControl with navigation title programmatically

I have a view controller whose navigation bar has a segment control. Now I want reuse this view controller to display something else with a title instead of a segment control. I tried to set the segment control's hidden propertory to true and set self.navigationController?.title = "foo", unfortunately, no title shows :(
How can I replace UISegmentedControl with my navigation title programmatically?
You have to set the titleView property of the navigationController to nil since the docs state
If this property value is nil, the navigation item’s title is displayed in the center of the navigation bar when the receiver is the top item. If you set this property to a custom title, it is displayed instead of the title. This property is ignored if leftBarButtonItem is not nil.
You can replace the UISegmentedView in the titleView like this
self.navigationItem.titleView = nil
self.navigationItem.title = "Title"

How to add Navigation bar to view controller with tab bar item

I have an app that uses bottom tabs aswell as a side menu, to have the button that initiates the side menu i use the typical three line menu button, to put that there I have a Navigation Bar. With the bar in place there is no way I can get the bar to be on top of the screen. I built it with interface builder, and heres a screenshot. The question is how do i have the navigation bar alone without the other grey bar above it?
The issue you're encountering is due to the fact that you're manually creating a navigation bar for your view controller, instead of using the bar that you get for free by embedding the view controller in a tab bar controller, hence the reason you see two bars. The other answer suggesting hiding the auto-generated navigation bar is not the correct solution. Instead, you should place your menu button and view title in the auto-generated bar instead of manually creating your own (you almost never want to do that, in-fact).
So what you should do instead is set the title property of your view controller to be "News", and the leftBarButtonItem property of the view controller to be your hamburger menu button (an instance of UIBarButtonItem initialized with an image for the icon).
For example (inside your view controller's viewDidLoad method or wherever appropriate):
self.title = #"News";
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"menuIcon"] style:UIBarButtonItemStylePlain target:self action:#selector(showSideMenu)];
If you want to remove the topmost navigation bar you need use self.navigationController.navigationBarHidden = YES; for view controllers that used for tabs in UITabBarController:
// StoriesViewController.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navigationController.navigationBarHidden = YES;
}

How would I implement nested Tab Bar Controllers in an IOS project

I"m trying to implement something like in the wireframe I basically want a Tab Nav Controller on the bottom, and then within on of the views, have another tab like controller. I'm just a little confused as to where I would start with this.
I very much doubt there's a standard user control for that top tab-like control that you want. You may have to construct your own controller and view for that, then manually manage the center view when you get taps on your "View 1" and "View 2" labels.
you should use not Tab Bar Controller, but Navigation Controller toolbar property. It looks like tab bar items but there's no need in implementation another controller instance.
Look at the UINavigationController reference page
A navigation controller object manages an optional toolbar in its view
hierarchy. When displayed, this toolbar obtains its current set of
items from the toolbarItems property of the active view controller.
When the active view controller changes, the navigation controller
updates the toolbar items to match the new view controller, animating
the new items into position when appropriate.
This is some UIViewController class:
- (void)createToolbarItems
{
UIImage *background = [[UIImage imageNamed:#"navbar"] resizableImageWithCapInsets:UIEdgeInsetsMake(2, 2, 2, 2)];
[self.navigationController.toolbar setBackgroundImage:background forToolbarPosition:UIBarPositionBottom barMetrics:UIBarMetricsDefault];
self.navigationController.toolbar.delegate = self; // optional
//... create some UIBarButtonItem items
self.toolbarItems = #[item1, space, item2, space, item3, space, item4]; // we set items not to navigation controller instance, but the current controller
}
- (void)showToolbarAnimated:(BOOL)animated
{
if(!self.toolbar)
return;
[self.navigationController setToolbarHidden:YES animated:animated];
}

Update back button in navigationbar

if i change the title of the parentViewController, how do i update the back button displayed in the upper left corner of the child view. ?
i already know to set self.title when i am actually displaying the parent view, but i would like to know how to refresh the button with the new title displayed in the child view while i am looking at the child view. i have tried
self.parentViewController.title = #"foo"
and
self.parentViewController.navigationItem.title = #"foo"
Try this:
self.parentViewController.navigationItem.backBarButtonItem.title = #"foo";
You need to set the title for the navigationItem that belongs to the 'previous' controller. So in a navigationController that would be the one 'to the left'.
You can set this title first and then push the new view onto the stack.
What I ended up doing was implementing a delegate protocol. my child view tells the parent the new name and the parent sets its title. with self.title = #"foo"

Resources