I am trying to build an iPhone application that has a Tab bar as the root controller and several navigation bars. My doubt is, shall I create one NavigationBarController class for each navigation bar that I want to put in the application? Or is it possible to create only a single navigation controller that manages all the navigation bar controllers that exist in the application?
In the case that multiple navigation controllers exist in the application, can I use the "self" to access the correct navigation controller that pushes/pops the view? Or should I use the delegate of the Application delegate to access each navigation bar controllers?
(I am assuming that all navigation bar controllers are declared in the application delegate, is this approach correct or is there a more elegant approach?)
Thanks a lot in advance
The common way to achieve this is to create a Tab Bar application and then change each item in the tab bar to be a UINavigationController. If you do this, you can definitely use self to access the navigationController - specifically you can use self.navigationController.
Watch out for possible leak in this part of the above code:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:tools];
You could use this instead:
UIBarButtonItem* rightButtonBar = [[UIBarButtonItem alloc] initWithCustomView:tools];
self.navigationItem.rightBarButtonItem = rightButtonBar;
[rightButtonBar release];
;) ... or use autorelease
Insert a unique UINavigationController for each tab.
You can't have a single controller manage across multiple tabs, since a navigation controller can only have a single linear stack of view controllers. Each tab should have it's own navigation controller with a different root controller in each one.
The common way to achieve this is to create a Tab Bar application and
then change each item in the tab bar to be a UINavigationController.
This is THE way of achieving this. I have loaded 5 navigation controllers into a tab bar controllor. The key tip is to plan the navigations of the App, as every navController should take place where a new navigation tree starts.
Related
I have a little problem related to implementing a tabbar with navigationcontrollers, when I have two views before the tabbarcontroller, which also uses a navigationcontroller.
This is my setup in StoryBoard
http://i.stack.imgur.com/8P4Zw.png
http://i.stack.imgur.com/ei3xa.png
But this is not working as I want, because I get two navigationbars (Picture number 2) when I enter the tabbar screen. I know I just can delete the navigation controllers in the tabbar or change the segue to modal, but if I do so, I would not have the ability to add individuel UIBarbuttons to each tabbar view or set individuel navigationbar titles. I would also like to use the push segue through out the app, as it is a kind of an "step by step" app. My question is: How I can eliminate the double navigationbar, when I enter the tabbar, but still have the ability to set a title for each view related to the tab and continue to use the push segue and a navigationcontroller?
I hope you understand my question.
You -can- set individual buttons for each view controller. Grab a tab bar item and drag it to the navigation bar of whichever view controller you want. You can also set the individual title of each view controller. Like you said, there is no reason for the 2nd and 3rd navigation controller you added right after the tab bar controller.
You can set buttons both in the Storyboard and programmatically and they can be different at different stages of your view controller. You should thus delete the second and third navigation controllers and either drag and drop the buttons you want where you need them, and/or deal with it programmatically if necessary.
One example of what you could do programmatically:
UIBarButtonItem *yourButton = [[UIBarButtonItem alloc] initWithTitle:#"yourTitle" style:UIBarButtonItemStylePlain target:self action:#selector(yourSelector)];
self.navigationItem.leftBarButtonItem = buttonSegueBackToAccueil;
This creates a UIBarButtonItem for the controller you are in and places it as the left button of the navigation controller bar. It will run the method "yourSelector" when clicked.
I need to present a modal tab bar controller using interface builder. I'd like to be able to specify and design the tab bar controller in a InfoViewController.xib file, then present it from a variety of locations within the application using something like:
UIViewController *vc = [InfoViewController create];
[self presentModalViewController:vc animated:YES];
I don't know how to setup the interface builder file. I can drag in a tab bar view controller, but it is not displayed when the view controller is presented. How should I link up this tab bar controller with the file owner?
You're over thinking this. Just do exactly what you said you were going to do. Reusability is a good thing.
Interface Builder is for designing your views.
You choose how and when to present them (e.g. modally) inside your code.
I ended up defining the tab bar controller in each XIB it was being presented from (currently only one). Not the ideal situation, but could not figure out how to do it from an external reusable XIB.
Here is my problem:
I've read a lot about how to use a tab bar within a navigation based application, but i still can't figure it out. I have tried both to use and avoid using a tab bar controller, but i just can't find the solution.
I already have a navigation based app working. I have several nib files (views), each one with its own view controller, that i programmatically push onto the navigation controller stack. I need one of this views to have a tab bar that allows me to switch between some of the others. I understand how the tab bar works, and i do think what i need is to use a tab bar controller, since it would allow me to define the view controllers associated with each tab bar item, and manage all about them. However, i can't see how to do it.
If i do declare a tab bar controller in my "tabBarViewController", draw the tab bar controller in my "tabBarView" and link them with the IB, it will give me an error (I reckon this is because i haven't really pushed the tab bar controller's view? do i need something equivalent to "[window addSubView:[tabbarcontroller view]]?). In this case, all i need to know is how to "see" the tab bar controller's top view controller's view within a view controller i have already pushed.
If i try not to use a tab bar controller, as i have read is the best solution to this problem, ¿how do i manage tab bar items, the switchs between them, etc?
I would really appreciate your help.
You can't push a tab bar controller onto a navigation controller stack. There's just no supported way to do it.
What you may want to consider instead is creating your own instance of UITabBar, then using a delegate that conforms to UITabBarDelegate. That way, your delegate will receive the tabBar:didSelectItem: message whenever a tab bar item is selected by the user. You'll have to manage the NSArray of items for the bar yourself, though, without using IB.
Once you've got that figured out, all that's left to do is push a regular UIViewController onto your navigation stack like any other, and just have that controller manage your tab bar and delegate.
I just made an App with a tabBar controller and 5 navControllers. All you need to do is load the nibs and navigation controller inside the first element of the tabBar controller. You can HIDE the tabBar even if the views are inside it, and make it appear in the view you need it to.
You can do this with a bit of code, like so:
FooViewController *foo = [[FooViewController alloc] init];
BarViewController *bar = [[BarViewController alloc] init];
UITabBarController *tabby = [[UITabBarController alloc] init];
[tabby setViewControllers:[NSArray arrayWithObjects:foo, bar, nil] animated:NO];
[self.navigationController pushViewController:tabby animated:YES];
[foo release];
[bar release];
[tabby release];
You could probably do it with IB as well, just load the tab bar controller from a nib.
I built a sample project that demonstrates this in action, you can download it from http://s3.thismoment.com/navtab.zip
I am using my own custom navigationBar, but i need to access it in a number of different views because i need to add buttons, change title and so forth.
Should i pass a reference to my navigationBar each time i show a new view, or just make it a singleton so i can access it from any view?
Neither.
You've listed adding buttons and changing titles as the reasons you need a custom toolbar, but both of those things can be done through the navigation controller with no need to create your own and therefore no need to create a singleton or a global variable.
When you push a new view controller, you can set the title for the navigation bar simply by calling [self setTitle:#"Nav Title"]; in the -viewDidLoad of that view controller. If you need to add a button, use code like the following (also in -viewDidLoad):
[[self navigationItem] setRightBarButtonItem:[[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemEdit
target:self
action:#selector(setEditing)] autorelease]];
In other words, your design is flawed if you are creating a custom navigation bar only for the reasons you've listed. I suppose there are some good reasons to create a custom navigation bar, but these are not among them.
Consider reviewing the Configuring the Navigation Item Object section of the View Controller Programming Guide for iPhone OS.
Best regards,
Are you using a UINavigationController? If so, you can access the navigation bar from any sub-controller like this:
UINavigationBar *bar = self.navigationController.navigationBar;
Make it a global variable.
I'm trying to implement a UI structured like in the Tweetie app, which behaves as so: the top-level view controller seems to be a navigation controller, whose root view is an "Accounts" table view. If you click on any account, it goes to the second level, which has a tab bar across the bottom. Each tab item shows a different list and lets you drill down further (the subsequent levels don't show the tab bar).
So, this seems like the implementation hierarchy is:
UINavigationController
Accounts: UITableViewController
UITabBarController
Tweets: UITableViewController
Detail view of a tweet/user/etc
Replies: UITableViewController
...
This seems to work[^1], but appears to be unsupported according to the SDK documentation for -pushViewController:animated: (emphasis added):
viewController: The view controller that is pushed onto the stack. It cannot be an instance of tab bar controller.
I would like to avoid private APIs and the like, but I'm not sure why this usage is explicitly prohibited even when it seems to work fine. Anyone know the reason?
I've thought about putting the tab bar controller as the main controller, with each of the tabs containing separate navigation controllers. The problem with this is that each nav controller needs to share a single root view controller (namely the "Accounts" table in Tweetie) -- this doesn't seem to work: pushing the table controller to a second nav controller seems to remove it from the first. Not to mention all the book-keeping when selecting a different account would probably be a pain.
How should I implement this the Right Way?
[^1]: The tab bar controller needs to be subclassed so that the tab bar controller's navigation item at that level stays in sync with the selected tab's navigation item, and the individual tab's table controller's need to push their respective detail views to self.tabBarController.navigationController instead of self.navigationController.
The two previous answers got it right - I don't use UITabBarController in Tweetie. It's pretty easy to write a custom XXTabBarController (plain subclass of UIViewController) that is happy to get pushed onto a nav controller stack, but still lives by the "view controller" philosophy. Each "tab" on the account-specific view (Tweets/Replies/Messages) is its own view controller, and as far as they are concerned they're getting swapped around on screen by a plain-ol UITabBarController.
I'm building an app that uses a similar navigation framework to Tweetie. I've written a post about how to do this on my blog www.wiredbob.com which also links to the source code. It's a full template you could take and use as a basis for another project. Good luck!
It's possible to add a UITabBar to any UIViewController. That way you don't actually have to push a UITabBarController and therefore stay within the guidelines of the Apple API.
In interface builder UITabBar is under "Windows, Views & Bars" in the Cocoa Touch Library.
I do this in a couple of my apps. The trick to adding a tab bar to a navigationController based app is to NOT use a TabBarController. Add a Tab Bar to the view, make the view controller for that view a TabBarDelegate, and respond to user selections on the tab bar in the code of the view controller.
I use Tab Bars to add additional views to the Tab Bar's view as sub-views, to reload a table view with different datasets, to reload a UIPickerView, etc.
I was struggling for the past hour to implement a UITabBar because it would get hidden when I tried to display my view; then I found this post:
Basically, make sure you insert your new view below the tabbar, per this line of code:
[self.view insertSubview:tab2ViewController.view belowSubview:myTabBar];
In my app, the root view controller is a UINavigation controller. At a certain point in the app, I need to display a UITabBar. I tried implementing a UITabBar on a UIView within the navigation hierarchy, as some of the previous posts suggested, and this does work. But I found that I wanted more of the default behavior that the tab controller provides and I found a way to use the UITabBarController with the UINavigation controller:
1) When I want to display the UITabBarController's view, I do this:
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
appDelegate.window.rootViewController = myUiTabBarControllerInstance;
2) When I want to return to where I was in the navigation hierarchy, I do this:
appDelegate.window.rootViewController = myNavControllerInstance;
This could be achieved by simply embedding the TabBarController in the Navigation Controller.
In the storyboard:
Drag a ViewController
Click on the ViewController's Scene
Click on editor >> Embed in >> Navigation Controller.
Drag a button on the same ViewController.
Drag a TabBarController
Connect the button on the ViewController to the TabBarController via push Segue Action.
In this case only the TabBarController's RootViewController would be in the Navigation Controller's stack. All The TabBarItems would have the Navigation Bar at the top and user can go to Home Screen at any time, irrespective of the selected TabBarItem
This could be done at any ViewController in the Navigation Controller's stack.
If it works, please suggest me how to increase the reputation so that I can post the images and the code in the next answer. :)
This is how i did it. This is actually pushing a tabbarcontroller onto navigation controller. It works fine. I didn't find anywhere in the documentation that apple doesn't support this way. Can someone give me link to this warning?
If this is truth, is it possible that apple refuses to publish my app to appstore?
-(void)setArrayAndPushNextController
{
MyFirstViewController *myFirstViewController = [[MyFirstViewController alloc] init];
MySecondViewController *mySecondViewController = [[MySecondViewController alloc] init];
myFirstViewController.array = self.array;
NSArray *array = [[NSArray alloc] initWithObjects:myFirstViewController, mySecondViewController, nil];
UITabBarController *tab = [[UITabBarController alloc] init];
tab.viewControllers = array;
[array release];
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:#"first title" image:nil tag:1];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:#"second title" image:nil tag:2];
myFirstViewController.tabBarItem = item1;
mySecondViewController.tabBarItem = item2;
[self stopAnimatingSpinner];
[self.navigationController pushViewController:tab animated:YES];
[tab release];
[item1 release];
[item2 release];
}
I wrote a blog post on how I approached this problem. For me, using a modal view was a simpler solution than writing a custom tab-bar implementation.
http://www.alexmedearis.com/uitabbarcontroller-inside-a-uinavigationcontroller/