I am trying to understand what is a proper structure of the objects when using uinavigationcontroller with a tab bar.
I want my app to have the following structure: welcome/login screen -> 3 bar tabs.
I have the following objects/classes:
AppDelegate
WelcomeViewController
TabController
FirstTab
SecondTab
ThirdTab
I have also created a uinavcontroller under WelcomeViewController once the user clicks on "enter" to the app:
-(IBAction)aMethod:(id)sender {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FirstView *controller = [[FirstView alloc] initWithNibName:#"FirstView" bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
self.window.rootViewController = self.navigationController;
navigationController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navigationController animated:YES];
}
My question is - how should I manage the tab bar - where should I declare each one of its pieces, and will I need to create a uitabbarcontroller in this case (in which case, where?)).
I am very confused as to how to place the different tab bar related declarations and none of the examples/ tutorials our there were able to clarify this for me.
BTW - I started this app from a view based application.
Thanks!
You can either set this up in code or you can do it using interface builder.
I prefer the interface builder method as you can visually see the structure of your view controllers.
This is how I do it...
In your AppDelegate.h add a property
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
In your AppDelegate.m firstly synthesize the property
#synthesize tabBarController = _tabBarController;
Set up the application:didFinishLaunchingWithOptions: method to look something like this (you may do more work in this method)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self.window addSubview:self.tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
In MainWindow.xib drag a Tab Bar Controller object onto your objects area (this is where your AppDelegate and Window objects are).
Ctrl + Drag from the AppDelegate to the Tab Bar Controller object and select the property that we just made.
NOTE: Now we have a Tab Bar Controller set up and ready to roll.
There should be two tabs set up as an example. If you just want to use sub classes of UIViewController then just change the classes of these objects to represent your UIViewController sub classes.
If you want to use UINavigationController then drag a UINavigationController object onto your Tab Bar Controller object.
Now click the disclosure triangle on UINavigationController and change the class of its ViewController to be your custom subclass of UIViewController.
Related
I have been searching and experimenting on this for a while, but I just can't find out what I'm doing wrong.
I want to make an app with a menu, and from that menu, you can get to a TableViewcontroller with a title bar. I found out that, in order to get this title bar, you need to "insert" UITableViewController into a UINavigationController. this is where I'm stuck.
let's not mind / forget the menu from the app for now, because i know how to switch view controllers when user taps a button.
in my AppDelegate.m I have:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
TableViewController *tableView = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
self.navController = [[UINavigationController alloc] initWithRootViewController:tableView];
self.window.rootViewController = navController;
[self.window makeKeyAndVisible];
return YES;
}
in my AppDelegate.h file I Have:
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
UINavigationController *navcontroller;
}
#property (strong, nonatomic) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
I have 2 classer, UITableViewController and NavigationView.
In the UITableViewController, I made an array called tableRows:
tableRows = [[NSArray arrayWithObjects:#"1", #"2", nil] init];
the numberOfSectionsInTableView is set as 1 and the numberOfRowsInSection is set as return tableRows.count;
I left my NavigationView.m untouched, except that I tried to set a title in it.
in my NavigationView.xib, I tried to make the connection between the UITableViewController and the UINavigationController.
I added an NSObject, and changed its class to AppDelegate
I replaced the View for a UIWindow and connected the window property from my
AppDelegate.h to it
I added a UINavigationController and
connected it with the navController from my AppDelegate.h.
and last, I changed the class from the RootView from the
UINavigationController to UITableViewController.
Now my problem is, with or without the connections in IB, whatever I try to change in my table, or in the titlebar, it does not change when I run the app.
Does anybody know what I'm doing wrong? I'm using xcode 4.6, so lots of the tutorials I've checked are not very useful, because they are made with older versions of xcode. please help me, Thank you in advance!
in you AppDelegate replace this line
TableViewController *tableView = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
with this
TableViewController *tableView = [[TableViewController alloc] initWithStyle:UITableViewStylePlain];
You're not creating an instance of TableViewController but instead UITableViewController so thus you're not getting any of your code executed. (You should have a compiler warning for this in your app delegate - make sure to heed those warnings). Likewise you're not loading the NavigationView nib anywhere - you're creating a navigation controller with the table as the root view controller. It's not clear what your objective for NavigationView is so I can't provide a recommendation for how to proceed. However, for the table view, change the following line in your app delegate
TableViewController *tableView = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
to
TableViewController *tableView = [[TableViewController alloc] init];
In your table view xib, make sure File's Owner's class is set to be of class TableViewController (not UITableViewController). Right click on the table view and drag the circles next to 'data source' and 'delegate' to file's owner. Then right click file's owner and make sure the circle next to 'view' is connected to the table view. Save, clean, and run.
You might also find it very useful to checkout the free Sensible TableView framework. The framework will take your array and automatically generate all the table view cells, while managing all the details required to correctly setup the navigation controller. Hope this helps.
I have a Tab-bar application in iOS Storybords. The UITabbarcontroller is connected to -->4 sets of (UInavigation controller--> UItableview controller). Each UITableviewcontroller cells are connected to multiple UIviewcontrollers to be pushed.
On building the app -The navigation tab appears on the top of the view controllers without any problem. But the Tabbar with 4 items at the bottom is visible ONLY on the first view. The UIviewcontrollers does not display the 4 item Tabbar!??. I have set the bottom bar to tab bar in the attributes inspector. But it doesn't work?
I believe there must be more to it than I understand. Hope somebody helps.
How to display the tabbar through out the app?
I'm not totally sure of your design, but here are a couple of tips that hopefully may help.
storyboard design:
basic tabbar application layout would generally look like this from left to right with the first controller on the left having the little arrow indicating it is the starting controller.
your first controller should be the tabbar controller
each tab should be connected to a navigation controller
each navigation controller should be connected to one or more UIViewControllers or UITableViewControllers.
now, note while there are advanced configurations, this is just the general layout that sets up the app nicely and gives easy push transitions for each tab.
if your app starts off and shows the tabbar and when you select a tab item it should show the view controller for that tab. if the tabbar is still there, then you are in good shape up to that point. If you select something on that view controller and it pushes a new view controller on screen and when that happens you lose the tabbar bar, then its likely this is the issue:
- check your view controllers and look in the object inspector for a check mark called "hides bottom bar on push" - if it is checked - then uncheck it.
If you don't find it there, then inspect your code for your view controllers and look in the startup methods like view did load for the statement: self.hidesBottomBarWhenPushed = YES; if you find that command, comment it out or delete it.
It is perfectly ok to hide the tabbar on some view controller pushes if that is your design and makes sense in your application. Generally, it's a good practice to try and avoid it and leave the tabbar on screen when possible for user experience but sometimes issues like screen size might lead the developer down a path of hiding it for some workflow.
I hope this helps and ties back to your question. if not, sorry.
You can add tab bar like this way:-
Appdelegate.h
#import <UIKit/UIKit.h>
#class StartingViewController;
#interface Appdelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
StartingViewController *viewController;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet StartingViewController *viewController;
#property (nonatomic,retain) UITabBarController *tabBarController;
-(void)addTabBarToView;
#end
app delegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
[self addTabBarToView];
return YES;
}
-(void)addTabBarToView{
FirstController *first = [[FirstController alloc] initWithNibName:#"FirstController" bundle:nil];
first.title = #"First";
SecondController *second = [[SecondController alloc] initWithNibName:#"SecondController" bundle:nil];
second.title = #"Second";
ThirdController *three = [[ThirdController alloc] initWithNibName:#"ThirdController" bundle:nil];
first.title = #"Third";
Forthcontrooler *Four4 = [[Forthcontrooler alloc] initWithNibName:#"Forthcontrooler" bundle:nil];
second.title = #"Secfor";
UINavigationController *navigationController1 = [[UINavigationController alloc] initWithRootViewController:first];
UINavigationController *navigationController2 = [[UINavigationController alloc]initWithRootViewController:second];
UINavigationController *navigationController3 = [[UINavigationController alloc] initWithRootViewController:three];
UINavigationController *navigationController4 = [[UINavigationController alloc]initWithRootViewController:Four4];
tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects:navigationController1,navigationController2,navigationController3,navigationController4,nil];
[window addSubview:tabBarController.view];
}
Put the UINavigationControllers inside the UITabbarControllers instead of the other way around
New to iOS development, I've been following the tutorials on developer.apple.com, and am now adding functionality to those examples to further my knowledge.
The "second ios app" tutorial gives you a navigation controller based app. Extending this app, I want to have a tab bar controller as the first view controller.
So I now have the following setup:
All good. But there is code in the BirdsAppDelegate (a UIApplicationDelegate) which was relying on the navigation controller being the root view controller, so it can create and assign the "datacontroller" object.
This is the original code (before I added the tab bar controller):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
BirdsMasterViewController *firstViewController = (BirdsMasterViewController *)[[navigationController viewControllers] objectAtIndex:0];
BirdSightingDataController *aDataController = [[BirdSightingDataController alloc] init];
firstViewController.dataController = aDataController;
return YES;
}
Now this code fails because it assumes the root view controller is the navigation controller.
I have updated the code so that it works - but in my opinion it is ugly, and would have to be changed every time I make a change to the view controller hierarchy:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *navigationController = (UINavigationController *) [[tabBarController viewControllers] objectAtIndex:0];
BirdsMasterViewController *firstViewController = (BirdsMasterViewController*) [[navigationController viewControllers] objectAtIndex:0];
BirdSightingDataController *aDataController = [[BirdSightingDataController alloc] init];
firstViewController.dataController = aDataController;
return YES;
}
So my question is: What is the better way to do what I am doing in the code above, so that any changes to the hierarchy will not break the code?
How do I programmatically access the view controller I am after in the application delegate, so that I can create and assign it's BirdSightingDataController object?
Thanks!
You can loop the [navigationController viewControllers] array looking for an instance of BirdsMasterViewController... Using [obj isKindOfClass:[BirdsMasterViewController class]].
You don't even need that code at a all. If you just want to change the controller, go to the storyboard and select the viewController you want to change to a TabBarController. In the Editor menu, there is an option for "Embed In", the choices are TabBar and Navigation controllers.
I always start with a single view application template. There is no code in the "application didFinishLaunchingWithOptions:" method,(except to return YES). You can set any viewController as your initial view in the storyboard, by setting the is initial View Controller check box, or just dragging the arrow to the viewController you want as your initial view.
I wanted to add a navigation controller to a view based application . how can we do this both programmatically and using xib file..
If you need to incorporate a navigation controller in your uiviewcontroller you need to initialize it as it follows
UIViewController *yourViewController = ...
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:yourViewController];
[self presentModalViewController:navController animated:YES];
//you need to release the controller
[navController release];
If you are in the UIApplicationDelegate method
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
You can't do a presentModalViewController:navController animated... then you need to add the navController.view to the window
UIViewController *yourViewController = ...
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:yourViewController];
[self.window addSubview:navController.view];
//don't do a release of navController because is not retained by addSubview
UINavigationController *navcontroller = [[UINavigationController alloc] initWithRootViewController:viewController];//here viewController is to which you want to make the navigation
[self.view addSubView:navController.view];
You can just drag a "Navigation Bar" from your objects in the bottom right corner of Interface Builder. This basically does what Sachin says in his answer but you still have to programmatically create the functionality of the navigation controller. I.e pushing new views to the stack and poping them off.
In my opinion it's easiest to do it entierly in the code.
If you want to have a navigation controller as the root view for your main window. Then you can do so by using the following code.
#interface yourAppDelegate_iPad : NSObject <UIApplicationDelegate> {
UINavigationController *navigationController;
}
#property (nonatomic, retain) UINavigationController *navigationController;
#end
#implementation yourAppDelegate
#synthesize navigationController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
navigationController = [[UINavigationController alloc] initWithRootViewController:yourRootViewController];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
You can do this by using the xib as follows
Open the MainWindow.xib
Drag and drop a UINavigationController to it.
Create and connect the outlets.
Open attributes for the navigation controller and set the root
view.
I have created a new application using the View Based Application Template in xCode.
My first view, which displays on loading the app, is a button based menu. One of the buttons (Make) should load a new navigation stack using a NavigationViewController. There are other buttons that when implemented will do other things outside of NavigationViewController's scope.
I would like to be able to click Make and open and display a new navigation controller.
From ViewController.m:
-(IBAction)makeStory:(id)sender{
NSLog(#"makeStory:");
navController = [[UINavigationController alloc] init];
makeStoryTableViewController = [[MakeStoryTableViewController alloc] initWithNibName:#"MakeStoryTableViewController" bundle:nil];
[navController pushViewController:makeStoryTableViewController animated:YES];
}
I have created a NavigationViewController in the opening ViewController.h file:
#import <UIKit/UIKit.h>
#import "MakeStoryTableViewController.h"
#interface StoryBotViewController : UIViewController {
UINavigationController *navController;
MakeStoryTableViewController *makeStoryTableViewController;
}
- (IBAction)makeStory:(id)sender;
#end
I know I'm missing something because when I call pushViewController nothing happens - I think that somehow I have to attach the NavigationViewController to the ViewController that makeStory: is in.
For reference, my app delegate header declares the view controller in the #implementation as follows:
UIWindow *window;
StoryBotViewController *viewController;
with the appropriate #synthesize in the .m of the app delegate
#synthesize window;
#synthesize viewController;
How do I push a NavigationStack on from my opening view controller?
Please forgive me if the question is a little vague, I'm happy to provide more information if you need it. It's my first time questioning on stackoverflow and I'm obviously a bit of a newbie with the iPhone SDK.
you had it almost. But you forgot to add the NavigationController to your view.
[self.view addSubview:navController.view];
Add this in your IBAction.
EDIT:
but much likely this is not what you want, because you can't navigate back to your very first viewController. If you want to navigate back to the first viewController set up your project like in the navigation-based template. You can to this programmatically to:
Move all UINavigationController stuff from the header file of the viewcontroller to the app delegate header. And change your app delegate implementation to something like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
navController = [[UINavigationController alloc] initWithRootViewController:viewController];
// Add the view controller's view to the window and display.
// [window addSubview:viewController.view];
[window addSubview:navController.view];
[window makeKeyAndVisible];
return YES;
}
make sure to release navController in dealloc
then replace your IBAction with something like this:
- (IBAction)makeStory:(id)sender {
makeStoryTableViewController = [[MakeStoryTableViewController alloc] initWithNibName:#"MakeStoryTableViewController" bundle:nil];
[self.navigationController pushViewController:makeStoryTableViewController animated:YES];
}
if you don't like to display the navigationbar in your first viewcontroller hide it, but make sure to unhide it if you push other items on the stack. self.navigationController.navigationBar.hidden = ...