I'm surprised that not "more" has been asked about this :-)
My app is a standard tab bar controller with multiple sections. Each section (tab) contains a navigation controller that controls a couple of view controllers (your basic tableview + detailview type of setup). Now that I've added a 6th tab, iOS creates the default "More" tab that controls the final two tabs. I need to eliminate the "More" text in the middle of the navigation bar (Note: Not the button text, nor the title of the tab itself), and apply a custom background image to the navigation bar.
Note: This question is about customizing the "More" navigation bar - I've successfully modified the background image and titleView text on all of the non-iOS created navigation bars.
In my app delegate, the app is put together thusly:
Create View Controllers:
ViewController1 *vc1 = [ViewController1 alloc] initWithNibName#"View1" bundle:nil];
vc1.title = #"VC1";
vc1.tabBarImage.image = [UIImage imageNamed:#"image1.png"];
Repeat the above routine 5 more times for view controllers vc2 through vc6.
Create the individual navigation controllers:
UINavigationController *nc1 = [UINavigationController alloc] initWithRootViewController:vc1];
Repeat 5 more times for nav controllers nc2 - nc6.
Add Nav Controllers to Tab Bar Controller
self.tabBarController.viewControllers = [NSArray arrayWithObjects: vc1, vc2, vc3, vc4, vc5, vc6, nil];
All of the code above works perfectly. No issues.
I then add a custom background image to the More navigation controller thusly:
if (self.tabBarController.moreNavigationController){
if ([self.tabBarController.moreNavigationController.navigationBar respondsToSelector:#selector(setBackgroundImage:forBarMetrics:)] ) {
UIImage *image = [UIImage imageNamed:#"navlogo.png"];
[self.tabBarController.moreNavigationController.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];
} else {
UINavigationBar *navbar = self.tabBarController.moreNavigationController.navigationBar;
UIImage *headerImg = [UIImage imageNamed:#"navlogo.png"];
[navbar setBackgroundImage:headerImg forBarMetrics:UIBarMetricsDefault];
}
}
This too works just fine. No issues
Since my custom background contains the client's logo dead center, I need to remove the text of the titleView that by default reads "More". Note, I'm not talking about the text of the Navigation BUTTON, but the label in the middle of the navigation bar.
Logically, one would assume that this would work:
UILabel *label = [[UILabel alloc] init];
label.text = #"";
self.tabBarController.moreNavigationController.navigationItem.titleView = label;
...because I do this in all of individual view controllers, substituting self.navigationItem.titleView for self.tabBarController.moreNavigationController, etc.
But this doesn't work! I can successfully change both the background image and the titleView text on all of my navigation controllers with this exact same code (again, substituting self.navigationController.navigationItem for the moreNavController stuff...). However, in the app delegate, I can only set the background image, but not the titleView of the More nav controller.
Any solutions would be greatly appreciated.
VB
Turns out, my original code was correct, just in the wrong place.
UILabel *label = [[UILabel alloc] init];
label.text = #"";
self.tabBarController.moreNavigationController.navigationBar.topItem.titleView = label;
However, I was previously executing this before I added the tabBarController as my rootViewController
The correct order is:
self.window.rootViewController = self.tabBarController;
UILabel *label = [[UILabel alloc] init];
label.text = #"";
self.tabBarController.moreNavigationController.navigationBar.topItem.titleView = label;
Posting Swift5 version as it took me quite some time to make it work properly
moreNavigationController.viewControllers[0].tabBarItem = UITabBarItem(title: "My Title", image: UIImage(named: "MoreTab")!, tag: 1111)
moreNavigationController.navigationBar.topItem!.title = "My Title"
Please note that changing moreNavigationController.tabBarItem doesn't work quite well. I do this in viewDidLoad() of a class which extends UITabBarController
E.g., in application:didFinishLaunchingWithOptions: of the Tab Controller iOS Template
// Override point for customization after application launch.
UITabBarController *tabBarController = (UITabBarController *)(self.window.rootViewController);
UINavigationController *moreNavigationController = tabBarController.moreNavigationController;
moreNavigationController.navigationBar.topItem.title = #"";
This changes the navigation bar title, but leaves the tab label title as "More".
I found one
Swift 2.2
Put this in didFinishLaunchingWithOptions
tabBarCtr.moreNavigationController.delegate = self
tabBarController.moreNavigationController.viewControllers.first?.title = ""
Implement this delegate method
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool)
{
navigationController.navigationBar.topItem?.rightBarButtonItems = nil
navigationController.viewControllers.first?.title = ""
}
This will also remove the edit button on top of more navigation controller navigation bar.
This might not be applicable to everyone on the thread but for me... I had a tabBarController with > 5 items... I needed to set the title on the automatically generated moreNavigationController... it was as simple as specifying self.title=#"title" in the viewDidLoad method of the target detailviewcontroller.
You can change the title inside the viewDidLoad function
self.title = #""
Related
I want to create a Tab Application with a header image that is always present, no matter what Tab Item is active.
The example would be Foursquare:
I want to be able to place buttons and have different information displayed on that header.
Is that a simple Navigation Bar or something else?
Usually, for each tab is associated a viewController. You can notice it in the boilerplate which xcode creates when you choose "Tabbed Application".
Then, in each viewDidLoad or in the init of each viewcontroller you can set:
self.navigationItem.titleView=[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"image.png"]];
Then just change self.navigationItem.leftBarButtonItem and self.navigationItem.rightBarButtonItem with your controls on each viewController.
Edit:
In the appDelegate (in the didFinishLaunchingWithOptions method) you've to set something like this if you want use the navigationcontrollers:
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
UINavigationController *myNav1=[[UINavigationController alloc] initWithRootViewController:viewController1];
UINavigationController *myNav2=[[UINavigationController alloc] initWithRootViewController:viewController2];
UIImage *navBackgroundImg = [UIImage imageNamed:#"bg_navBar.png"];
UIImage *tabBackgroundImg = [UIImage imageNamed:#"bg_tabBar.png"];
[myNav1.navigationBar setBackgroundImage:navBackgroundImg forBarMetrics:UIBarMetricsDefault];//iOS 5 only
[myNav2.navigationBar setBackgroundImage:navBackgroundImg forBarMetrics:UIBarMetricsDefault];//iOS 5 only
[[UITabBar appearance] setBackgroundImage:tabBackgroundImg];//iOS 5 only
self.tabBarController.viewControllers = [NSArray arrayWithObjects:myNav1, myNav2, nil];
self.window.rootViewController = self.tabBarController;
Looks like a simple navigation bar, but they aren't exactly simple. You need to place/create a NavigationItem on the bar (after placing/creating the bar itself) and then set the titleView to a custom view with your image. According to the documentation the left bar button (close in your first screen) has to be nil or else the titleView is ignored. Though you can place buttons in this custom view for left buttons.
I found out the easiest thing to do is to write:
- (void)viewDidLoad
{
[[UINavigationBar appearance] setBackgroundImage:
[UIImage imageNamed:#"UINavigationBar.png"] forBarMetrics:UIBarMetricsDefault];
}
At my MainViewController, and all Navigation bars that get created on each view controller gets configured like that.
I am wondering why my UINavigationController is not letting me set a title. It lets me change the tint of the navigationBar, but the title and rightBarButtonItem I set just get ignored. Why?
Here's my code:
taps = 0;
UIView*controllerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
controllerView.backgroundColor = [UIColor whiteColor];
controller = [[UIViewController alloc] init];
[controller setView:controllerView];
[controllerView release];
navController = [[UINavigationController alloc] initWithRootViewController:controller];
navController.navigationBar.barStyle = 1;
navController.navigationItem.title = #"Setup";
UIBarButtonItem*item = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonSystemItemDone target:self action:#selector(dismissSetup:)];
navController.navigationItem.rightBarButtonItem = item;
[item release];
[self presentModalViewController:navController animated:YES];
[mp stop];
p.s: I know i'm not releasing some of the stuff I alloc'ed, I do that later!
set: self.title = #"This is my title"; in the viewController
(or in your case set controller.title = #"this is my title";)
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.
You want your UINavigationController to change its title depending on which viewcontroller is currently on top. So the way to go is to set the title in the viewcontrollers you are pushing onto the viewControllers array.
And by the way: I don't think navigationcontrollers are supposed to be presented modally:
Because the UINavigationController
class inherits from the
UIViewController class, navigation
controllers have their own view that
is accessible through the view
property. When deploying a navigation
interface, you must install this view
as the root of whatever view hierarchy
you are creating. For example, if you
are deploying the navigation interface
by itself, you would make this view
the main subview of your window. To
install a navigation interface inside
a tab bar interface, you would install
the navigation controller’s view as
the root view of the appropriate tab.
I have a UITabBarController which has been created programatically, which has 6 tabs. As such the MoreNavigationController is automatically created to take care of having more than 5 tabs. Everything looks fine when the MoreNavigationController is displayed, but when I select one of these rows to push the view controller on to the stack, the cell image (tab bar image) disappears. When I pop that view controller, the image remains hidden until the pop animation is completed, at which point the image suddenly appears again.
This is fairly old code and I wouldn't do it this way these days, but everything works except for this last little thing so I'm pretty hesitant to rip out all the code and do it another way. Can anyone suggest what I might be doing wrong?
An example of creating one of the tab bar view controllers:
InfoViewController* infoViewController = [[InfoViewController alloc] init];
infoViewController.tabBarItem.image = [UIImage imageNamed:#"90-life-buoy.png"];
infoViewController.tabBarItem.title = #"More Info";
infoViewController.title = #"More Info";
UINavigationController* infoNavController = [[UINavigationController alloc] initWithRootViewController:infoViewController];
[infoViewController release];
Creating the tab bar:
tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects:outdoorsNavController, peopleNavController, citiesNavController, landscapesNavController, infoNavController, basicsNavController, nil];
[window addSubview:tabBarController.view];
EDIT: Doesn't seem to make any difference whether I use retina (#2x) images or not.
The issue is because you're wrapping your InfoViewController in a UINavigationController.
When you click on the table row in MoreNavigationController, the controller uses the tabBarItem in UINavigationController while it does its transition. Because this is nil (in your code), the image in MoreNavigationController disappears. When the transition finally finishes, MoreNavigationController picks up the tabBarItem in InfoViewController
Try this:
InfoViewController* infoViewController = [[InfoViewController alloc] init];
infoViewController.tabBarItem.image = [UIImage imageNamed:#"90-life-buoy.png"];
infoViewController.tabBarItem.title = #"More Info";
infoViewController.title = #"More Info";
UINavigationController* infoNavController = [[UINavigationController alloc] initWithRootViewController:infoViewController];
//Set the tabBarItem for UINavigationController
infoNavController.tabBarItem = infoViewController.tabBarItem
[infoViewController release];
Here's a video reproducing and fixing the issue:
Item 7 has an empty tabBarItem.image while Item 6 has tabBarItem.image set
I'm not sure, but have you tried setting the NavigationCotroller's .tabBarItem?
Not sure if I understand correctly, but on the top of my head here are some suggestions (The More Tab Bar item shouldn't disappear at all times, that is created automatically)
Have you tried subclassing your UINavigationController that is being used for the MoreController's place and set its tab bar items properties there, therefore making sure you have control over its lifetime ?
Subclass your UIViewController's that you wish to push onto the navigation stack and have them use the same tab bar item ?
Mimic the default functionality, create your own UITableViewController to act as the More Controller, and at each tap of the rows, do what you want, also in a custom way.
PS: Try setting images name without the .png extension. This way you will automatically load the #2x resource as well. Eg: [UIImage imageNamed:#"90-life-buoy"]
Link
So, I want my app starts with a UIViewController(without seeing a tabbar), and then enter a UITableView with navigationbar and tabbar. the problem is that the Tabbar is visible at the app starts up, anyone can help on this will be very appreciated...
I think you should either send -presentModalViewController:animated: to your main UIViewController with the tab bar controller as an argument or just do this:
[myWindow addSubview: myTabBarController.view];
Make your app a navigation based application (rather than a tab bar based one) then add a tab bar on the UITableView.
There is help for adding the UITabBar here
I do it like this : in this case drawing a table view and map view (From the Locati application)
tabBarController = [[UITabBarController alloc] init]; // creates your tab bar so you can add everything else to it
searchTableViewController = [[SearchTableViewController alloc] init]; // creates your table view - this should be a UIViewController with a table view in it, or UITableViewController
UINavigationController *searchTableNavController = [[[UINavigationController alloc] initWithRootViewController:searchTableViewController] autorelease];
[searchTableViewController release]; // creates your table view's navigation controller, then adds the view controller you made. Note I then let go of the view controller as the navigation controller now holds onto it
searchMapViewController = [[SearchMapViewController alloc] init];
UINavigationController *mapTableNavController = [[[UINavigationController alloc] initWithRootViewController:searchMapViewController] autorelease];
[searchMapViewController release]; // does exactly the same as the first round, but for your second tab at the bottom of the bar.
tabBarController.viewControllers = [NSArray arrayWithObjects:searchTableNavController, mapTableNavController, nil]; //add both of your navigation controllers to the tab bar. You can put as many controllers on as you like
I found this pattern a long time ago. Sorry that I can't point at the original.
YOu then need to add the tabbarcontoller to the relevant view ([...view addSubView:tabBarController];) possibly setting frame first.
Hey all. I'm still pretty new to iPhone development, and I'm having a bit of trouble figuring out how to change the title of my Navigation Bar. On another question on this site somebody recommended using :
viewController.title = #"title text";
but that isn't working for me...Do I need to add a UINavigationController to accomplish this? Or maybe just an outlet from my UIViewController subclass? If it helps, I defined the navigation bar in IB and I'm trying to set its title in my UIViewController subclass. This is another one of those simple things that gives me a headache. Putting self.title = #"title text"; in viewDidLoad and initWithNibName didn't work either. Anybody know what's happening and how to get it happening right?
Thanks!
The view controller must be a child of some UINavigationController for the .title property to take effect. If the UINavigationBar is simply a view, you need to push a navigation item containing the title, or modify the last navigation item:
UINavigationItem* item = [[UINavigationItem alloc] initWithTitle:#"title text"];
...
[bar pushNavigationItem:item animated:YES];
[item release];
or
bar.topItem.title = #"title text";
if you are doing it all by code in the viewDidLoad method of the UIViewController you should only add self.title = #"title text";
something like this:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"title";
}
you could also try self.navigationItem.title = #"title";
also check if your navigationItem is not null and if you have set a custom background to the navigationbar check if the title is set without it.
There's one issue with using self.title = #"title";
If you're using Navigation Bar along with Tab bar, the above line also changes the label for the Tab Bar Item. To avoid this, use what #testing suggested
self.navigationItem.title = #"MyTitle";
If you want to change navbar title (not navbar back button title!) this code will be work.
self.navigationController.topViewController.title = #"info";
If you want to change the title of a navBar inside a tabBar controller, do this:
-(void)viewDidAppear:(BOOL)animated {
self.navigationController.navigationBar.topItem.title = #"myTitle";
}
In my navigation based app I do this:
myViewController.navigationItem.title = #"MyTitle";
I had a navigation controllers integrated in a TabbarController. This worked
self.navigationItem.title=#"title";
By default the navigation controller displays the title of the 'topitem'
so in your viewdidload method of your appdelegate you can. I tested it and it works
navController.navigationBar.topItem.title = #"Test";
UINavigationItem* item = [[UINavigationItem alloc] initWithTitle:#"title text"];
...
[bar pushNavigationItem:item animated:YES];
[item release];
This code worked.
If you are working with Storyboards, you can click on the controller, switch to the properties tab, and set the title text there.
I guess you need a dynamic title that is why you don't set it in IB.
And I presume your viewController object is the one specified in the NIB?
Perhaps trying setting it to a dummy value in IB and then debug the methods to see which controller has the dummy value - assuming it appears as the title...
From within your TableViewController.m
:
self.navigationController.navigationBar.topItem.title = #"Blah blah Some Amazing title";
For all your Swift-ers out there, this worked perfectly for me. It's notably one of the shorter ways to accomplish setting the title, as well:
override public func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "presentLineItem" {
print("Setting Title")
var vc = segue.destinationViewController as! LineItemsTableViewController
vc.navigationItem.title = "Line Item"
}
}