I've been stuck trying to puzzle this out for a couple days now, and I'll admit I need help.
The root view controller of my application is a tab bar controller. I want to have each tab bar a different navigation controller. These navigation controllers have completely different behavior.
So how do I set this up in terms of classes? Per Apple's documentation, I'm not supposed to subclass UINavigationViewController. So where do I put the code that drives each of these navigation controllers? Does it all get thrown in App Delegate? That would create an impossible mess.
This app should run on iOS 4.0 or later. (Realistically, I can probably require iOS 4.2.)
This is taken from one of my applications. As you say, you are not supposed to subclass UINavigationController, instead you use them as they are and you add viewcontroller on the UINavigationController's. Then after setting the root viewcontroller in each UINavigationController, you add the UINavigationController to the UITabBarController (phew!).
So each tab will "point" to a UINavigationController which has a regular viewcontroller as root viewcontroller, and it is the root viewcontroller (the one you add) that will be shown when a tab is pressed with a (optional) navigationbar at top.
UITabBarController *tvc = [[UITabBarController alloc] init];
self.tabBarController = tvc;
[tvc release];
// Instantiates three view-controllers which will be attached to the tabbar.
// Each view-controller is attached as rootviewcontroller in a navigationcontroller.
MainScreenViewController *vc1 = [[MainScreenViewController alloc] init];
PracticalMainViewController *vc2 = [[PracticalMainViewController alloc] init];
ExerciseViewController *vc3 = [[ExerciseViewController alloc] init];
UINavigationController *nvc1 = [[UINavigationController alloc] initWithRootViewController:vc1];
UINavigationController *nvc2 = [[UINavigationController alloc] initWithRootViewController:vc2];
UINavigationController *nvc3 = [[UINavigationController alloc] initWithRootViewController:vc3];
[vc1 release];
[vc2 release];
[vc3 release];
nvc1.navigationBar.barStyle = UIBarStyleBlack;
nvc2.navigationBar.barStyle = UIBarStyleBlack;
nvc3.navigationBar.barStyle = UIBarStyleBlack;
NSArray *controllers = [[NSArray alloc] initWithObjects:nvc1, nvc2, nvc3, nil];
[nvc1 release];
[nvc2 release];
[nvc3 release];
self.tabBarController.viewControllers = controllers;
[controllers release];
This is how I go from one viewcontroller to another one (this is done by tapping a cell in a tableview but as you see the pushViewController method can be used wherever you want).
(this is taken from another part of the app)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.detailedAnswerViewController == nil) {
TestAnsweredViewController *vc = [[TestAnsweredViewController alloc] init];
self.detailedAnswerViewController = vc;
[vc release];
}
[self.navigationController pushViewController:self.detailedAnswerViewController animated:YES];
}
The self.navigationcontroller property is of course set on each viewcontroller which are pushed on the UINavigationController hierachy.
Related
Hihi all,
I am pretty new in iPhone dev. I have follow some tutorial and created a tabbar application. Below is the code in the appdelegate implementation:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *viewController1 = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil];
UIViewController *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
Then set the title and the image for the tab in each of the controller implementation.
My problem is that, example, in my viewController1, I need to navigate to viewController3, when I use presentModalViewController method to push the viewController3 in, the tabbar at the bottom will be disappeared.
While I tried to use the app delegate to refer to my tabBarController, and use tabBarController.navigationController pushViewController method, my viewController3 is not being pushed, and seems nothing happens.
I have tried to follow a few tutorial, but it's all required to drag in the navigationcontroller into the MainWindow.xib, which, in the xcode 4, MainWindow.xib doesn't exist anymore. How can i create the navigationcontroller from code so that the app can navigate between different view without hiding the tabbar?
Any comment is very much appreciated! Thanks in advance!
:)
If you want to use a navigation controller, you need to create a navigation controller. Since you're not using a XIB, you'll have to create it manually.
Since you want the tab bar to remain visible when you present viewController3, you need to make the navigation controller a child of the tab bar controller.
UIViewController *viewController1 = [[ViewController1 alloc] initWithNibName:#"ViewController1" bundle:nil];
UINavigationController *navController1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
UIViewController *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:
navController1,
viewController2,
nil];
Then when you want to present viewController3, do this:
// in some method of viewController1
[self.navigationController pushViewController:viewController3 animated:YES];
I am not very Sure but have you tried this??? Actually i am going to use XCode 4 soon, i am still using 3.2.8 version:-
WebViewController *viewController = [[WebViewController alloc]initWithNibName:#"WebViewController" bundle:nil];
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:viewController animated:YES];
[viewController release];
See in this also the Tab bar will be removed when you navigate to your 3rd screen, you have to provide the navigation bar to come back.
Hope it helps.. :)
My UITabBar is not completely showing after I present a UITabBarController from a UIViewController. Please can you tell me what I am doing wrong?
My code is:
//some method
LoggedInViewController *lvc = [[[LoggedInViewController alloc] initWithAccount:account] autorelease];
[self presentModalViewController:lvc animated:YES];
- (void)viewDidLoad
{
self.tabController = [[UITabBarController alloc] init];
LoggedInFeedNavigationController *navController = [[LoggedInFeedNavigationController alloc] initWithAccount:self.account];
[self.tabController setViewControllers:[NSArray arrayWithObject:navController]];
[self.view addSubview:self.tabController.view];
[super viewDidLoad];
}
It's not a good practice to do:
[viewController1.view addSubview:viewController2.view];
The point of the MVC design is lost. The view controller should get your data (from the model) and put it in the view. If you have more than one view just arrange the functionality of the views to accept the corresponding data.
So if you need a tab bar controller you should do the following:
// assuming you are in the same initial controller
UITabBarController* pTabBarControllerL = [[UITabBarController alloc] init];
MyFirstController* pFirstControllerL = [[MyFirstController alloc] init];
[pTabBarControllerL setViewControllers:[NSArray arrayWithObject:pFirstControllerL]];
// perhaps set more tab bar controller properties - button images and so on
[self presentModalViewController:pTabBarControllerL animated:YES];
// release the memory you do not need
-(void)viewDidLoad {
// do your work in pFirstControllerL
}
PS: You should not subclass UINavigationController and UITabBarController.
Actually according to the Apple's recommendations UITabBarViewController should be the root in the UIWindow hierarchy. We had hard times trying to put TabBar VCs or Navigation VCs not to the root.
I currently have a UINavigationController in my app delegate where I push a ViewController on to login. If the login is successful I want to then create a UITabBarController with a Navigation Controller as the first Tab whose root controller is a UIViewController that I am creating.
The RootViewController of my first UINavigationController is actually acting as a delegate to the logincontroller so if a user logs in correctly it calls a method in my RootViewController which is where I would then like to push a UITabBarController onto the stack. Here is my code:
UITabBarController *tbController = [[UITabBarController alloc] init];
FileBrowserViewController *fileController = [[FileBrowserViewController alloc] init];
fileController.pathToFileDB = pathToDBUnzipped;
fileController.parentId = #"0";
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:fileController];
NSMutableArray *aViewControllersArray = [[NSMutableArray alloc] initWithCapacity:2];
[aViewControllersArray addObject:navController];
[navController release];
[tbController setViewControllers:aViewControllersArray];
[self.navigationController pushViewController:tbController animated:YES];
[tbController release];
Now, it is all working fine. Except 2 things. Here is the screen shot:
1) I can't see any uitabbar items. How do i set an image and the text for each tab?
2) I don't want that top black bar. I only want 1 bar ontop with the undo button. How do I remove the additional bar?
I always follow this approach when I have both a UINavigationController and a UITabbarController:
You need to start with a view based application. And then create a UITabbarController in your appDelegate file.
Appdelegate.h
UITabBarController *tabBarController;
// set properties
Appdelegate.m
// Synthesize
tabBarController = [[UITabBarController alloc] init];
tabBarController.delegate=self;
// Adding Search,Nearby,Map,AboutUs,Favorites Tabs to tabBarController
Search * search = [[Search alloc] init];
UINavigationController *searchNav = [[UINavigationController alloc] initWithRootViewController:search];
Nearby* nearby = [[Nearby alloc] init];
UINavigationController *nearbyNav = [[UINavigationController alloc] initWithRootViewController:nearby];
Map* map = [[Map alloc] init];
UINavigationController *mapNav = [[UINavigationController alloc] initWithRootViewController:map];
AboutUs* aboutUs = [[AboutUs alloc] init];
UINavigationController *aboutUsNav = [[UINavigationController alloc] initWithRootViewController:aboutUs];
Favorites* favorites = [[Favorites alloc] init];
UINavigationController *favoritesNav = [[UINavigationController alloc] initWithRootViewController:favorites];
NSArray* controllers = [NSArray arrayWithObjects:searchNav,nearbyNav,mapNav,aboutUsNav,favoritesNav, nil];
tabBarController.viewControllers = controllers;
[window addSubview:tabBarController.view];
You can accordingly manage in which tab you want to place navigation controller or only a view controller.
Then in each of the view controllers mentioned above you need to implement
- (id)init {}
in which you can set Tab name and image.
I always follow this approach and it never fails. The tabs are always visible. You can make changes according to your code.
to hide the above black bar use -
[self.navigationController setNavigationBarHidden:TRUE];
to set tab bar item use -
for system item -
UITabBarItem *firstItem = [[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemFavorites tag:0];
for custom item -
UITabBarItem *firstItem = [[UITabBarItem alloc] initWithTitle:#"title" image:[UIImage imageNamed:#""] tag:0];
[navController setTabBarItem:firstItem];
Here is a good video on how to combine Tab Bar, Navigation Bar, and/or Table Views.
http://www.youtube.com/watch?v=LBnPfAtswgw
If you don't want you sign-up screen to have a Tab Bar controller, then you will have to present it as a modal view (since the tab bar is your root view controller). This can be done through the presentModalViewController:animated: method. You can find info about that at:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html%23//apple_ref/doc/uid/TP40007457-CH111-SW1
I hope that helps. Let me know if you have any other questions!
Cheers, Evan.
hi friend that top bar is status bar . You can set.statusbar hidden = yes;
or change it from plist , when you open your plist there is a option to hide it,
I am editing my question that i had programetically add the tabbar as shown below:-
FirstViewController *obj_FirstViewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
SecondViewController *obj_SecondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
ThirdViewController *obj_ThirdViewController = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
navigation1 = [[UINavigationController alloc] initWithRootViewController:obj_FirstViewController];
navigation2 = [[UINavigationController alloc] initWithRootViewController:obj_SecondViewController];
navigation3 = [[UINavigationController alloc] initWithRootViewController:obj_ThirdViewController];
MainTabBar = [[UITabBarController alloc] init];
MainTabBar.delegate=self;
[MainTabBar setViewControllers:[NSArray arrayWithObjects:navigation1,navigation2,navigation3,nil]];
MainTabBar.view.frame=self.view.frame;
MainTabBar.selectedIndex=0;
[self.view addSubview:MainTabBar.view]
By writing this in (void)viewDidLoad i got the 3 tab in my viewcontroller.But the problem is i want to set the name of the tab as
Home
Favorites
About us
I had tried by writing the below code:-
obj_FirstViewController.tabBarItem.title=#"Home";
self.title = #"My View Controller";
But this does not work - can anyone please help me how to do this programatically? Where to write the line so that i get this 3 name in my tab bar
this is how I made it
1) I made a view controller with your tabbar
2) added view controllers for each tab and a method to the tabbar view controller class:
-(void)updateContentsWithViewController:(UIViewController *)insideViewController
the method is called when a tabbutton is pressed.
3) here is the code for the switching
- (void)updateContentsWithViewController:(UIViewController *)insideViewController {
//internalViewController is the viewController which you change
[internalViewController.view removeFromSuperview];
[internalViewController release];
internalViewController = [insideViewController retain];
navController = [[UINavigationController alloc] initWithRootViewController:insideViewController];
[navController setNavigationBarHidden:YES];
[navController.view setFrame:CGRectMake(0, 0, 320, 348)];
//frame I needed in my app .. can be changed
[self.internalView addSubview: navController.view];
//navController is the property for the navigationController
[self.view sendSubviewToBack: self.internalView];
}
its possible add tabBar in separate view controller which will be like rootview controller ,then in viewDidLoad of the root view controller assign the object of tabbar created to a appdelegate tabBar declared ...then use appdelegate tabbar for other navigation's alone .
I am working with push notifications. i am trying to create and push a DetailView in the navigationController when action button in notification is clicked. but navigationController is nil. how can i put that DetailView in the navigationController? I want to push RootViewController in the navigationController and then the DetailView. how can i do that?
in AppDelegate:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
RootViewController *controller = [[RootViewController alloc] init];
//getting warnings here.(Unused variable navigationController)
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[controller doStuff];
[controller release];
}
in RootViewController:
-(void)doStuff{
[[self stories] removeAllObjects];
[self startParsing];
[self.tableView reloadData];
DetailViewController *detail = [[DetailViewController alloc] init];
//custom code
[self.navigationController pushViewController:detail animated:YES];
[detail release];
this is the code i m using right now. and plz notice that i have
[self.tableView reloadData];
Okay, now I am pretty sure I understand the issue. The problem is, you never manually set the navigationController property on a UIViewController. The navigationController property is nil if the view controller is not under a navigation controller and if it is, then the property points to it.
What you need to do, is when you display your root view controller, instead of directly displaying its view, add it to a navigation controller, then display the navigation controller's view. Like so:
RootViewController *controller = [[RootViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
//Here you would display navigationController.view somehow
So, after you have your root view controller in a navigation controller, in a method in root view controller you can do this:
DetailViewController *detail = [[DetailViewController alloc] init];
//Do whatever you need to do to set values on the detail view controller
[self.navigationController pushViewController:detail animated:YES];
The key thing is this: you need to put the root view controller into a navigation controller before you can access a navigation controller from within root view controller.
If your nav controller is nil, it needs creating and then you place things into it.
Try this:
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[navController pushViewController:detailViewController animated:NO]; // or YES
If you start out with no UINavigationController and want to display it with more than one view controller in its stack, after initing the navigation controller you can set the viewControllers property to an array with the various view controllers you want.
edit: some example code:
UINavigationController *navController = [[UINavigationController alloc] init];
NSArray *viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
[navController setViewControllers:viewControllers animated:NO];
After doing that, your navigation controller will have viewController2 on top and viewController1 behind it.
Alternately, you could do it this way:
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController1];
[navController pushViewController:viewController2 animated:NO];