I have been having some trouble with the UITabBar and cannot find anything online in regards to the subject. Pretty much I want to display a view (say TestView) and a TabBar that contains to other views: Green View and Red View. So initially I want TestView displayed with a tabBar on the bottom with 2 tabs, one for Green view and one for Red View, once one of those tabs are touched the appropriate view will be displayed, but there will be no tab for the TestView
But heres the MainAppDelegate code and a picture of what I get
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Create the TabBar VC and ButtonSelect VC
testView = [[TestViewController alloc] init];
tabBarController = [[UITabBarController alloc] init];
//Create the viewcontroller's For the TabBarController
UIViewController *gvc = [[GreenViewController alloc] init];
UIViewController *rvc = [[RedViewController alloc] init];
//Make a array to containing the two viewcontrollers (for TabBar)
NSArray *viewControllers = [NSArray arrayWithObjects:gvc, rvc, nil];
//Attach the VC's to the TabBar
[tabBarController setViewControllers:viewControllers];
//Set to window
[window addSubview:[tabBarController view]];
[window addSubview:[testView view]];
[window makeKeyAndVisible];
[rvc release];
[gvc release];
return YES;
}
And This is what I get..
Please help
Adjust the frame of your testView. For example,
testView = [[TestViewController alloc] initWithFrame: CGRectMake(
0.0, 20.0, 320.0, 421.0)];
I used "magic numbers" here, but you had better get the height of the status bar and tab bar.
to the comment
So you want to dismiss the test view when the user selects one of the tab. You can catch the moment when a tab is selected by setting a delegate to the UITabBarController and implement tabBarController:didSelectViewController:` method. Basically, you will dismiss the test view in this method.
One way of doing it (and without changing your code much) is to set your application delegate as the delegate of the UITabBarController, (tabBarController.delegate = self;). Then implement tabBarController:didSelectViewController:, where you remove the test view from your application window and do tabBarController.delegate = nil;.
Related
I have an UITabBarController added programmatically one ViewController as ModalViewController.
It acts perfectly normal, when touching/switchen between the tabs.
But when touching the selected tab again, the delegate didselectviewcontroller did not get called.
Strange behaviour, if I setup a new project with TabBarController template, this is acting normal and everytime I touch a tab its delegate is being called.
What I noticed, if I touch 2-5px above the tabbar, the tab is being touched and the delegate is being called.
There is no view above the tabbar, I checked this 100 times.
if I touch in the lightgray area, the touch on the tab is being fired.. thats a miracle to me, anybody any idea?
Code:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.tabBarController = [[UITabBarController alloc] init];
_splashScreen = [[SplashScreenController alloc] initWithNibName:#"SplashScreenView" bundle:nil];
self.window.rootViewController = _splashScreen;
[self.window makeKeyAndVisible];
if finished loading data in background,
//getting UIViewControllers from Config and adding to NSMutableArray *tbcArr;
[self.tabBarController setViewControllers:tbcArr];
self.tabBarController.customizableViewControllers = nil;
self.tabBarController.delegate = self;
[self.splashScreen presentModalViewController:self.tabBarController animated:YES];
My project is a view based project to start off.
So app delegate launches as per normal.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Then my first viewcontroller is called and it shows two UITextFields so the user can enter their credentials and log on.
When that succeeds I call another view controller in which I add a UINavigationController and a UITabBarController to the view. As can be seen below.
- (void)viewDidLoad
{
[super viewDidLoad];
UINavigationController *localNavigationController;
tabBarController = [[UITabBarController alloc] init];
NSMutableArray *localControllersArray = [[NSMutableArray alloc] initWithCapacity:2];
Hello *firstViewController;
firstViewController = [[Hello alloc] init];
localNavigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
[localNavigationController.tabBarItem initWithTitle:#"Test" image:[UIImage imageNamed:#"tabBarIcon.png"] tag:1];
//[localNavigationController.tabBarItem initWithTabBarSystemItem:UITabBarSystemItemDownloads tag:1];
firstViewController.navigationItem.title=#"New Requests";
[localControllersArray addObject:localNavigationController];
[localNavigationController release];
[firstViewController release];
Test *secondViewController;
secondViewController = [[Test alloc] init];
localNavigationController = [[UINavigationController alloc] initWithRootViewController:secondViewController];
[localNavigationController.tabBarItem initWithTitle:#"Test" image:[UIImage imageNamed:#"tabBarIcon.png"] tag:2];
secondViewController.navigationItem.title=#"Existing";
[localControllersArray addObject:localNavigationController];
[localNavigationController release];
[secondViewController release];
// load up our tab bar controller with the view controllers
tabBarController.viewControllers = localControllersArray;
// release the array because the tab bar controller now has it
[localControllersArray release];
// add the tabBarController as a subview in the window
[self.view addSubview:tabBarController.view];
}
This seems to work ok, so far. There was a problem off both the Navbar and Tabbar being dropped to low by the height of the status bar, but that was corrected once i hid the status bar.
Is there any reason I should not do things this way? Is it bad practice or will i run into some problems with it down the road?
I could set up both the Navbar and the Tabbar from the app delegate and just hide them both during the log-on screen. That's the only other option I see.
I appreciate any feedback that you guys can offer. I feel nervous about the results of what I have done so far, expect it might blow up in my face.
Many Thanks,
-Code
You should generally not directly add the views of UINavigationController and UITabBarController as subviews of your own view controllers. This kind of 'view controller containment' is tricky to get right unless you use the new iOS 5 APIs.
The reason is that the actual view controllers will not receive certain important messages like viewDidAppear: and rotation messages. You will notice strange rotation bugs and other weird issues cropping up. You can forward these methods yourself from the parent view controller and things will work OK, but in your case you have no need to do this because you're just trying to show a standard tab bar controller.
Generally you should have one view controller set up as the UIWindow's root view controller. This is normally a UINavigationController, UITabBarController, etc. The parent UIWindow will send rotation events and other messages to this controller. The standard 'container' controllers like UITabBarController will then forward these messages to their children so everything works correctly.
If I were you, I would always have the tab bar controller as the window's root view controller. When your app starts (i.e. in application:didFinishLaunchingWithOptions:), create an empty tab bar controller and set it up as the root view controller:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// create a basic empty tab bar controller
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
// ...
// Set up the window's root view controller
self.window.rootViewController = tabBarController;
// ...
}
Now, whenever you present stuff on the screen, it should be a child of the root view controller, in your case the tab bar controller.
So once the root view controller is set up, you can check to see if the user is already logged in. If they are, you can then set up your navigation controller and the tab items, and add them to the tab bar controller.
If the user is not logged in, you can show your login view controller over the top of the tab bar controller using presentModalViewController:animated::
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
// Set up the window's root view controller
self.window.rootViewController = tabBarController;
if (isUserLoggedIn()) {
[self setupTabsAndStuff];
} else {
LoginViewController *loginVC = [[[LoginViewController alloc] init] autorelease];
[self.tabBarController presentModalViewController:loginVC animated:NO];
}
// ...
}
The animated:NO will cause the login screen to be immediately visible after starting the app with no animation.
Once the user enters correct details you can again call your setupTabsAndStuff method and dismiss the login view controller again.
So to summarize:
Rather than having your own UIViewController into which you place the tab bar controller's view, just use the tab bar controller directly.
Install the tab bar controller as the window's root view controller. The tab bar controller will then correctly forward rotation events and other special messages to the view controllers it contains.
Always present views and view controllers as children of the root view controller. If you need to show something full-screen use presentModelViewController:animated
Try to set the frame of *tabBarController.
[tabBarController.view setFrame:self.view.bounds];
// add the tabBarController as a subview in the window
[self.view addSubview:tabBarController.view];
- (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];
MainPageDialog *overviewViewController = [[MainPageDialog alloc] initWithNibName:#"MainPage" bundle:nil];
UINavigationController *nav_obj = [[UINavigationController alloc] initWithRootViewController:overviewViewController ];
[self.viewController presentModalViewController:nav_obj animated:YES];
[overviewViewController release];
[self.window makeKeyAndVisible];
return YES;
}
This code shows the blue bar of navigation controller, but no buttons on it.It seems like to be that the UINavigationController allocated as empty.
Who knows what problems is?
UPD:Archive http://www.mediafire.com/?lbjjvl6fcue2q18
Please help me, I'm new in objective-c
You need to create the button for it, for example:
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:launcherView action:#selector(endEditing)];
self.navigationItem.leftBarButtonItem = doneButton;
[doneButton release];
The correct way to use a UINavigationController is to push view controllers on to it. That way they will be stacked and the navigation bar will be populated with a back button when it is case (i.e., when you can actually go back to a previous controller). You control the label that appears in the "back" button by defining the title of the controllers you push.
The technique shown in another answer (setting explicitly the button) is useful with defining the right button, if you ever need one.
You could try with this code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainPageDialog *overviewViewController = [[MainPageDialog alloc] initWithNibName:#"MainPage" bundle:nil];
UINavigationController* navigation = [[UINavigationController alloc] init];
[navigation pushViewController:overviewViewController animated:NO];
[overviewViewController release];
[window addSubview:[navigation view]];
[self.window makeKeyAndVisible];
return YES;
}
Instead of doing:
UINavigationController* navigation = [[UINavigationController alloc] init];
[navigation pushViewController:overviewViewController animated:NO];
you could also use initWithRootController, but to display the general case of how you push a view controller I preferred this one.
Notice that since you are pushing just a root controller, you should see no back button at the moment, but if you push a second view controller, then it will appear.
EDIT: I gave a look at your project. Summary of what you should try and do:
objects you need in your NIB: File's Owner (UIApplication), First Responder, FBFun App Delegate (iVkAppDelegate), Window (UIWindow); remove the rest;
File's owner delegate outlet is FBFun App Delegate;
FBFun App Delegate window outlet is Window.
With this simple setup (more or less what you have), use this code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UINavigationController* navigation = [[UINavigationController alloc] init];
//-- MainPageDialog *overviewViewController = [[MainPageDialog alloc] initWithNibName:#"MainPage" bundle:nil];
iVkViewController *overviewViewController = [[iVkViewController alloc] init];
overviewViewController.title = #"First";
[navigation pushViewController:overviewViewController animated:NO];
iVkViewController *overviewViewController2 = [[iVkViewController alloc] init];
overviewViewController2.title = #"Second";
[navigation pushViewController:overviewViewController2 animated:NO];
[overviewViewController release];
[window addSubview:[navigation view]];
[self.window makeKeyAndVisible];
return YES;
}
In the code above, as you notice, I instantiated twice your iVkViewController just to have a second controller to push onto the navigator.
Please, delete your existing app from the simulator, and the run this in order to see that the navigation bar is correctly created and you can go back from the second controller to the first one.
I removed usage of MainPageDialog, because the MainPage nib has many problems.
But I hope this skeleton is sufficient for you to go forward with your development.
You had missed the line as you are not adding view to window.Add this line in your code
[window addSubview:nav_obj.view];
I am creating an application which I want to have a view controller with buttons as the first view controller with no navigation bar, and then when the user selects a button a table view controller appears managed by a navigation controller.
At the moment I am setting up the navigation controller in the app delegate and setting the top view controller as the table view controller I want to start the navigation bar on. So far I can see the navigation bar but that is it when I transition from the first view controller to the table view controller.
Any help would be much appreciated as I have confused myself with this issue.
I'm not totally clear on what you are asking, so I might have it wrong, but here goes.
The top navigation bar is can be displayed or hidden by calling:
self.navigationController.navigationBarHidden = NO;
In the viewWillAppear method of your viewController. So set it to YES or NO depending on whether or not you want it to be displayed.
#Disco, you would do something like so:
// In the App delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CustomViewController *viewController = [[CustomViewController alloc] init];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
// In your button method
- (IBAction)loadUpTableViewController:(id)sender {
CustomTableViewController *tvc = [[CustomTableViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:tvc];
[self presentModalViewController:navigationController animated:YES];
[navigationController release];
[tvc release];
}
my first xib contains a ScrollView with a springboard like interface in MainWindow.xib:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
navController = [[UINavigationController alloc] init];
[navController setNavigationBarHidden:YES];
[window addSubview:navController.view];
[window sendSubviewToBack:navController.view]; }
When a button is clicked the FirstViewController appears with a tableview and a navigation controller:
- (void) buttonPushed:(id)sender {
FirstViewController *firstViewController = [[FirstViewController alloc] init];
[navController pushViewController:firstViewController animated:YES];
[firstViewController release];
[window addSubview:navController.view]; }
When I click the back button in Navigation Controller to go back to springboard, I get the springboard xib, but unresponsive to touches with a Navigation Bar on top!
- (void)goHome:(id) sender {
[self.view removeFromSuperview];
How can I go back to springboard screen (mainwindow.xib) without having the navigation bar stacked on top, and be responsive to touches ?
Why don't you set the springboard view to be the root view controller of your navigation controller and get rid of any UI in the window?
I think that the window shouldn't have any UI elements accept view of view controllers that are added to it (by navigation controller or by tab bar controller).
This way you won't have to reinvent the wheel for the first view to load from the springboard view and the back button will work properly.
You can set the navigationBarHidden property to false in the viewDidLoad method of the root view controller (the view controller of the springboard view).
Did you try calling [navController setNavigationBarHidden:YES]; in your mainview viewWillAppear callback ?
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UIViewController *rootController = [[MyRootViewController alloc] init];
navigationController = [[UINavigationController alloc]
initWithRootViewController:rootController];
[rootController release];
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
}