iPhone dev - UIViewController title, tabBarItem, tag - iphone

I have a UITabBarController that manages 5 View Controllers. I create their tab bar items in their "init" methods so that they will be displayed before the view is loaded. I'm just wondering what way I should do it, because there seems to be so many ways. For example, for my DatePickerViewController:
- (id)init {
if((self = [super init])) {
// ================ THIS ==========================
UIImage *clockIcon = [UIImage imageNamed:#"clockicon.png"];
UITabBarItem *localTabBarItem = [[UITabBarItem alloc]
initWithTitle:#"Date" image:clockIcon tag:0];
[self setTabBarItem:localTabBarItem];
[localTabBarItem release];
// ================ OR THIS ========================
[self setTitle:#"Date"];
UITabBarItem *localTabBarItem = [[UITabBarItem alloc] init];
[localTabBarItem setImage:[UIImage imageNamed:#"clockicon.png"]];
[self setTabBarItem:localTabBarItem];
[localTabBarItem release];
// ================ OR THIS ========================
UITabBarItem *localTabBarItem = [[UITabBarItem alloc] init];
[localTabBarItem setTitle:#"Date"];
[localTabBarItem setImage:[UIImage imageNamed:#"clockicon.png"]];
[self setTabBarItem:localTabBarItem];
[localTabBarItem release];
}
return self;
}
Which way should I do it? And why is there a title for both the tabBarItem and the View Controller? And I don't think I need the tag (which is set in the first method).
Thanks!!

Well in my opinion any of these ways are ok, it might be more readible when you declare the UIImage in one line and set it in a different line rather than doing it all inline, but at the end you get the same result.
The TabBarItems have a title which is the text that will show in the tab bar item iteself. View Controllers have a title for Navigation Controller purposes, the View Controllers title is displayed in the NavigationControllers NavBar when set. And you do need tags, tags is the way you tell the buttons apart when someone click on them (when u manage the TabBar on your own).

The reason there are several ways to set the title is for convienece. You may want to display one title in the navigation bar and one title in the tab bar.
This actually quite common since there is less space to display text in the tab bar.
Like many things in Cocoa, there is more than one way to do it. The only "correctness" you need to be concerned about is what works best for your situation.

Related

Setting image on tabbar items in special case(if tab bar taken on viewController)

I am taking tab bar controller on view controller rather than delegate, and used code what mentioned below.
tabController = [[UITabBarController alloc]init];
tabController.delegate = self;
scanView = [[ScanTicketView alloc] init];
searchView = [[SearchView alloc] init];
historyView = [[HistoryView alloc]init];
tabController.viewControllers=[NSArray arrayWithObjects:scanView,searchView,historyView, nil];
[self.navigationController pushViewController:tabController animated:YES];
It works, but now how to apply images to these views. Can anyone help me here.
Thanks in advance.
You can use:
viewController.tabBarItem.image = [UIImage imageNamed:#"imageName.png"];
if you want to apply the image only to selected view controller in Tab bar, then UITabBarController has a selectedViewController and a selectedIndex property also see tabBarController.tabBar.selectedItem.tag if this may help.
Tabbar controller has its own property of Image and Title.
Go through this UITabbar Tutorial to understand properly. You can set image through property window or even through coding also.
Best Luck !

Setting "More Navigation Controller's" titleView text

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 = #""

Single tab in UITabBar does not contain a UINavigationBar

I'm having a really strange issue. I've written an app with five tabs in a UITabBar. When I set the TabBarController's viewControllers property, I set it with five UINavigationControllers, so that each tab will have a UINavigationController within it.
Four of the tabs have it working perfectly. The navigation bar is there when I launch and switch to that tab. However, one of the tabs does not contain the UINavigationBar as I expected it to, and I can't understand why, because I initialized it exactly the same way I initialized all the others.
Here's some sample code from the AppDelegate.m file of initializing the individual view controllers:
SpotFilterViewController *spotList = [[SpotFilterViewController alloc] init];
navigationController = [[UINavigationController alloc] initWithRootViewController:spotList];
[tabs addObject:navigationController];
[navigationController release];
[spotList release];
MySpotViewController *mySpot = [[MySpotViewController alloc] initWithSpot:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:mySpot];
[tabs addObject:mySpot];
[navigationController release];
[mySpot release];
Note: navigationController was declared above.
Anyone else run into this problem before? Or anyone have any idea why this might be happening? Any help is much appreciated. Thanks!
The problem is that you are doing this:
[tabs addObject:mySpot];
instead of this:
[tabs addObject:navigationController];

MoreNavigationController images disappearing on select

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

Changing the navigationBar on pushViewController:

In my tabBar based app I have subclassed the UINavigationBar. Let's say I have three of them: BlueNavBar, BlackNavBar and RedNavBar. It looks something like this:
//BlueNavBar.m
- (void)drawRect:(CGRect)rect {
self.tintColor = [UIColor colorWithRed:65.0f/255.0f green:(156.0f/255.0f) blue:(215.0f/255.0f) alpha:1.0];
UIImage *image = [[UIImage imageNamed:#"blueNavBar.png"]retain];
[image drawInRect:rect];
[image release];
}
I've assigned the subclassed navigationbar for each tab with Interface Builder. That is working great, no problems there.
In some viewControllers however i want to change the navigationBar during "pushViewController". Let's say I want to change the current navigationbar (which is for e.g. BlueNavBar) to the RedNavBar. How can I do this programmatically, without Interface Builder?
It depends on how you've designed the view controller classes themselves. One way to design what you need would be to set the navigation bar type (i.e. colour) when you create the view controller, before you push it on the stack. Something like:
SomeViewController* someViewController = [[SomeViewController alloc] initWithNibName:#"SomeView" bundle:nil];
someViewController.navigationBarStyle = NBStyleRed; // NBStyleRed defined as an enum somewhere
[self.navigationController pushViewController:someViewController animated:YES];
[someViewController release];
The setter method for navigationBarStyle would then (re)create an appropriately-coloured navigation bar for the view controller.