I have a TabBarController set as main controller tab, where names were defined using interface builder. Now I would like to change its names programmatically.
How could it be done?
Updated to XCode 8
Since my original answer, a lot has happened: Swift 3, Storyboards, etc. Title is usually the one that all views share, and can be set in the attributes inspector
Also, for more control, you can always drag the UITabBarItem, and UINavigationItem elements from the designer view. You must drag them to the view that's gonna be displayed in the tab bar/navigation controller. Basically they store the info as "I wanna be displayed in tab bar like this".
Hello Scene is getting a TabBarItem added to it, so it can be configured.
These two elements behave exactly as accessing the view controller's .tabBarItem and .navigationItem properties via code. These properties always exist in code if they are child of the corresponding object (nav has navItem, and tab has tabItem), you don't need to add them in storyboard/xib to have them.
This last thing is kinda confusing, since in the storyboard/xib it appears you're adding them to the view controller, but in truth you're just saying "the nib will configure these properties too".
Original Answer
The name that appears on the tab bar comes from the UIViewController's title property,
self.title = #"Name me!";
You can change the title at any point, and it should update the text appearing on the tab bar item. But be wary, do this as soon as possible, ideally, in the init method in use (or initWithNibName:bundle:, or initWithCoder:).
The key here, is that the init methods are called as soon as the tab bar appears on screen, as it initialises all of its view controller. If you were to do it on viewDidLoad, that would only get called if you actually select the tab, then other family of calls, same goes for awakeFromNib, viewWillAppear:, viewDidAppear:, etc.
The idea of having a title on the UIViewController, is to keep things consistent. If you show that viewController on a UINavigationController, the navigation bar on top should use the title property, as it does when using back. The UITabBarController also respects the same title property and changes accordingly.
In terms of reusability, you should be setting the title only from the inside of the UIViewController subclass.
The way of the Nib
Using nibs or storyboards? If you have a UIViewController, you can give it the name straight up in the attributes inspector (or ⌥⌘4)
Unfortunately, if the File Owner is the UIViewController subclass, then you won't be able to access it this way, simply because, XCode registers the File Owner as an "External Object", and doesn't show a configuration panel for it. :(
Multiple titles, same view controller
But sometimes, you just want to have them named differently
// Modify the display title on the tab bar
self.tabBarItem.title = #"World";
// Modify the display title on the navigation bar
self.navigationItem.title = #"Hello World";
Screwing with the neighbours
Each UIViewController should handle his own name, what if you want to force it from the outside (and thus, completely violating the original thing I said about reusability)?
// Rename the other guy's .title property
[[self.tabBarController.viewControllers objectAtIndex:<#Index#>] setTitle:#"Hello World"];
// Or do as before, and rename the other guy's tab bar
[(UITabBarItem*)[self.tabBarController.tabBar.items objectAtIndex:<#index#>] setTitle:#"Hello World"];
You could also probably do it with the navigation item, but that would require more gymnastics than I'm comfortable with.
However it is possible to do it in code, it is better to set this directly in Storyboard. How?
Just tap the appropriate tab bar item inside controller (NOT INSIDE TABBAR CONTROLLER).
Then switch to attribute inspector on the Utilities panel.
Now you are able to change everything:-)
Swift 4+
tabBarController?.tabBar.items![1].title = "xx"
In your viewController.m
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
//Here you are setting title
self.title = NSLocalizedString(#"Title", #"Title");
}
return self;
}
This is how you can change the name and the image of the icon of a tab bar:
self.tabBarItem = [[[UITabBarItem alloc] initWithTitle:#"Main Tab" image:[UIImage imageNamed:#"maintab.png"]] autorelease];
You probably want to do this in UITabBarController::viewDidLoad in which case you need to set the view controller's title because the tab bar items are currently 0 at that point.
So use
[[self.viewControllers objectAtIndex:0] setTitle: #"Buga"];
[[self.viewControllers objectAtIndex:1] setTitle: #"Nuga"];
I'm using Xcode Version 8.2.1 (8C1002) and this works for me:
Related
I've been recently developing an app that uses a freeform view controller. Everything was fine until I wanted to set the button title label's text considering localization.
I tried to set the text multiple ways but nothing seems to work. At first I was instantiating the view controller from storyboard using its storyboardID like so :
self.dropDown = [self.storyboard instantiateViewControllerWithIdentifier:#"dropDown"];
but then I realized that I cant set controller's titles. Or at least I didn't know where to set them. I have them all connected via storyboard as properties. I tried to set the button's title in the viewDidLoad method of the DropDown.m class, nothing. I've also tried to set the title in the controller where I am presenting the dropDown like so:
[self.dropDown.priceAscendingButton.titleLabel setText:NSLocalizedString(#"priceAscending", nil)];
[self.dropDown.priceDescendingButton.titleLabel setText:NSLocalizedString(#"priceDescending", nil)];
[self.dropDown.dateAscendingButton.titleLabel setText:NSLocalizedString(#"dateAscending", nil)];
[self.dropDown.dateDescendingButton.titleLabel setText:NSLocalizedString(#"dateDescending", nil)];
but nothing worked ..
Could you please help me ?
Use this
[self.dropDown.priceAscendingButton setTitle:NSLocalizedString(#"priceAscending", nil) forState:UIControlStateNormal];
I'm currently writing an app with multiple users.
I would like to use the same "Profile" view in storyboard to display info for all the users.
The plan was to set the title of the "Profile" view and then push it.
- (void) pushGeneralProfileViewFrom:(UIViewController *)target usernameAsTitleOfView:(NSString *)title {
UIViewController *myView = [target.storyboard instantiateViewControllerWithIdentifier:#"GeneralProfileView"]; // created in storyboard, Feed View
myView.title = title;
[target.navigationController pushViewController:myView animated:YES];
}
This worked great. However, the "profile" view also has buttons that lead it to other views in the storyboard. Those views also display specific info for the relevant user.
I was planning to use the name of the backBarButtonItem to know the user I need to display the info for. While I can see the back button with the username in the simulator, I'm unable to get it's self.navigationController.navigationItem.backBarButtonItem.title or self.navigationItem.backBarButtonItem.title. Both return null.
What am I doing wrong?
Also, I have a feeling this is not the best practice to handle those kind of things. I've searched the web and so far haven't seen a better way to pass values to a view I'm pushing. Suggestions?
Thank you.
The backBarButtonItem that you see when your view controller is visible in the navigation controller interface is not the backBarButtonItem of this view controller. It is the backBarButtonItem of the second view controller, the one behind this one in the stack.
So what you want is this:
UIInteger c = [self.navigationController.viewControllers count];
UIViewController* vc2 = [self.navigationController.viewControllers objectAtIndex:c-2];
Now get the backBarButtonItem of the navigationItem of that view controller. Or just get its title if they are the same.
I'm attempting to create a custom tab bar controller with the following options:
Feed
Map
New
Camera
Search
The feed, map, camera, and search will each pull up their individual VC's, while new is supposed to be more of a functionality button. When the new tab item is pressed, the map view should be displayed, and the map should begin recording the user's location. I'm trying to use a UITabBarController to manage these views, but I cannot seem to figure out how to implement the functionality that I would like with the "New" tab. It seems as if I would need to implement a separate view controller for the "New" record and stop functionality but that doesn't seem right.
The functionality of record/stop should be similar to snapchat's big red button that takes a picture when you press it.
While I agree with Scott's comment that this is a bad UX, if you technically wanted to do it, you could subclass UITabBarController and in viewDidLoad you could add a UIButton subview to the the tab bar controller's tabBar:
[self.tabBar addSubview:yourCustomButton];
Thus, this button could have it's own action and selector to do whatever you want with.
Take a look at idevrecipes for an example.
I think you have to implement the container view controller yourself. I think you can't do that with UITabBarController.
I was going to dig up the idevrecipes example that shawnwall pointed out, but there's another possibly answer, assuming you want the New button to match the standard UITabBarButton appearance. I agree it may not be the best UI, but it's workable.
For starters, you would create a dummy view controller for the New item. I'm not saying you should duplicate the Maps controller or anything, I'm just saying create an empty view controller and stash to it (or it's location) in a property. Assuming you're creating your tab bar in application:didFinishLaunchingWithOptions:, it'd look something like this.
self.newViewController = [[UIViewController alloc] init];
self.newViewController.title = NSLocalizedString(#"New", nil);
self.newViewController.image = [UIImage imageNamed:"new.png"];
Drop that view controller at the appropriate location in the tab bar controller's viewControllers property.
Save a reference to the Maps controller the same way you saved one for the dummy New controller.
If you haven't already done do, set the delegate of your tabBarController to your app delegate. You may need to declare that your app delegate conforms to UITabBarControllerDelegate.
UITabBarDelegate gives you a few hooks for tracking changes to the tab bar. tabBarController:shouldSelectViewController: looks to be the appropriate place for us to hook in for your desired behavior.
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
if ([viewController isEqual:self.newViewController]) {
self.tabBarController.selectedViewController = self.mapViewController;
// Whatever logic you need to start the recording
return NO;
}
return YES;
}
The look of the user interaction's a little odd - the user tabs the middle item (New), but the item to the left (Map) gets selected. If you want the "tab bar triggers behavior" action, I'd go the idevrecipes route and make the button visually distinct. If you're married to the tab bar item look, though, I believe this is how you'd accomplish it.
I am learning iOS by following O'Reilly Headfirst iPhone Development 2e.
I am trying to assign the title to a viewcontroller so that it looks like this:
But even when I set the title (as shown in the picture below) the title bar is still blank when the app runs in the simulator. I am sure I am missing something really obvious, but this is all really new so don't know what box to check/setting to configure in the IDE. I'm stuck. What should I click?
You have to select the navigation bar and define a title. You're defining the View Controller title, it's not the same thing.
What you're doing is nothing like what the book is telling you to do. It tells you to set the view controller in a nib; you're using a storyboard. It tells you to set the title of the view controller's navigation item; you're setting it on the view controller itself. In other words you're doing something different from what the book is saying to do, and then you're complaining that something different results.
You can set in this way also, other than set it in the interface builder.
if you gonna define a title for uinavigation bar use self.navigationItem.title = #"your title"; <-- in viewDidLoad
if it's view controller title use:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
// self.title = #"your title";
}
return self;
}
if you are new to ios, I recommend not to use storyboard.
Not an answer, per se.
I did this tutorial too, and find the book helpful. Start over and use nibs. Choose the Master-Detail template. However, if you want to keep using storyboards, follow this tutorial that tells you how to create a tableview with a drill-down:http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1
It will tell you how to set the title. I suspect that you've created your navigation bar or tableview incorrectly if you can't click on the Navigation Item and see where to set 'Title' in the attributes window.
Make sure you have your navigation bar selected, as far as I can see now you have selected your viewcontroller and not your navigation bar. You can also double click on the navigation bar to set a title, it will appear in your attributes inspector as well.
I'm having a problem getting a UISearchDisplay's text value to be set programatically on load of the view by another view and my question is have I overcomplicated my problem and missed something or am I on the right track of thinking.
Here's the situation: I have a UITabBarController as my root view, there are 2 tabs, both have a UINavigationController setup so I can push views as needed.
Tab 1 has a UITableViewController which is populated with a list of categories.
Tab 2 has a MapView in it's main view but I have done a custom UINavigationItem view to put various buttons and a UISearchDisplay on the rightBarButtonitem area.
The mapview layout and custom navigation item are stored in the same nib as two separate view objects. In Tab 2's viewDidLoad(), I initialise the rightBarButtonItem programatically with:
UIBarButtonItem *btnItem = [[UIBarButtonItem alloc] initWithCustomView:buttonBar];
self.navigationItem.rightBarButtonItem = btnItem;
[btnItem release];
Everything fires up, buttonBar is wired up to an IBOutlet as searchWhat and I can talk to this object from within the mapview's controller class.
If the user is in Tab 1 and taps a cell, I want it to switch to Tab 2 and populate the searchWhat.text and then execute the search code as if someone had typed in the search themselves.
What i'm having trouble with is the order of load and populate on a view.
I can access the 2nd tab from the 1st without any problem and get it to appear with something like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Quick Category cell tapped at row %d", indexPath.row);
self.tabBarController.selectedIndex = 1; // change to the search view controller
//[self.tabBarController.selectedViewController viewDidAppear:YES];
UINavigationController *nav = (UINavigationController *)self.tabBarController.selectedViewController;
SearchViewController *srch = [nav.viewControllers objectAtIndex:0];
//NSLog(#"%#", [srch description]);
[srch queueSearchByType:kSearchTypeQuickCategories withData:[catList objectAtIndex:indexPath.row]];
[srch viewDidAppear:YES];
}
Don't worry about catList and SearchViewController, they exist and this bit works to switch tabs.
Here's the problem though, if the user starts the application and selects an item in tab 1, tab 2 appears but the values of the search display text don't get set - because viewDidLoad and viewDidAppear are called in another thread so the execution of queueSearchByType:withData: gets called while the view is still loading and setting up.
If the user selects tab 2 (therefore initialising the subview) and then selects tab 1 and an item, it can populate the search display text.
I can't just change the order of the tabs so that tab2 is first and therefore loads it's subviews to the navigation bar as the project specification is category search first.
Have I missed something very simple? What I need to do is wait for the second tab to fully appear before calling queueSearchByType:withData: - is there a way to do this?
At the moment, i've implemented a queue the search, check for a queue search approach, this seems to be a bit long winded.
Ok, I don't like answering my own question but it appears my fears were right, basically if you want a UINavigationItem that is a custom view (ie, to put a search bar and various other buttons up on the nav controller) and be able to switch to and populate them from another tab on a tab bar controller, then you need to put the subview in it's own class which is a subclass of UIViewController and then make delegation your friend (which it already is), i've provided an example in case anybody needs to repeat it which i've put on my blog HERE.
http://www.jamesrbrindle.com/developer/ios-developer/howto-add-a-custom-uinavigationitem-to-a-uinavigationcontroller-with-delegation.htm
If anyone disagrees and thinks this can be simpler, please let me know or rate this post