Help with navigation Controller, windows & subviews! - iphone

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];
}

Related

View is not displaying after pushing on navigationController stack

I am trying to use a navigation controller to push/pop views, but I don't want the bar at the top with the buttons; I'm doing the navigation UI myself.
So I created a navigationController in my AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[WSViewController alloc] initWithNibName:#"WSViewController" bundle:nil];
self.window.rootViewController = self.viewController;
self.navController = [[UINavigationController alloc]
initWithRootViewController: self.viewController];
[self.window makeKeyAndVisible];
return YES;
}
and then in my WSViewController, I have an IBAction method that pushes another view on the navigation stack (I've verified that it's doing this correctly; I see it on the stack):
- (IBAction)showInfo:(UIButton *)sender {
if (self.wsInfoViewController == nil) {
WSInfoViewController *wic = [[WSInfoViewController alloc] initWithNibName:#"WSInfoViewController" bundle:nil];
self.wsInfoViewController = wic;
}
[self.navigationController pushViewController:self.wsInfoViewController animated:YES];
}
But I'm not seeing the info view show up when I tap on the info button in my WSViewController (which is showing up just fine).
If I make the navigationController the root controller, then I do see the wsInfoViewController when I tap on the info button, however, I also get the navigation bar at the top, which I don't want!
So... first, am I wrong in thinking I can use a navigation controller this way (i.e. using it for stack purposes but not for any UI at all)?
Second, if I'm not wrong, why isn't the view I'm pushing onto the stack showing up? I'm guessing it's because I'm not hooking the navigation controller up to the window correctly, but I'm not sure how to do that.
Thanks!!!
Elisabeth
So I think I have the answer to my question. Which is, you must set up the navigation controller as the root view controller for the AppDelegate window in order to use it, otherwise, the window doesn't know about it. My WSViewController is still the root view controller for the navigation controller. And then to get rid of the navigation bar, you can hide it.
Here's the updated code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[WSViewController alloc] initWithNibName:#"WSViewController" bundle:nil];
// doesn't work!
//self.window.rootViewController = self.viewController;
self.navController = [[UINavigationController alloc]
initWithRootViewController: self.viewController];
// do this instead
self.window.rootViewController = self.navController;
[self.window makeKeyAndVisible];
return YES;
}
To hide the nav bar in the views, in each view where you want it hidden, add the following methods:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
This is working great so far!

Show login screen before tab-controller view

i have a tabBarController application and using .xib files for the interface not the storyboard
i have this code by default in the appdelegate
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[PopAdsFirstViewController alloc] initWithNibName:#"PopAdsFirstViewController" bundle:nil];
UIViewController *viewController2 = [[PopAdsSecondViewController alloc] initWithNibName:#"PopAdsSecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
i have created a Login View and don't know how to show it before the tabBarView and hide t after a successful login.
One way would be to show it as a modalView on launch. Dismissing upon successfull login?
eg:
UIViewController myLoginViewController = [[MyLoginViewController alloc] init withNibNamed:"MyLoginViewController"]; //Or whatever you instantiation is
[myTabViewController presentModalViewController:myLoginViewController animated:YES];
And to dismiss it (Hide it)
//This should be done from the original View Controller i.e. myTabViewController preferably in a delegate called by the modal view controller.
[self dismissModalViewControllerAnimated:YES];
Documentation on modalViewControllers:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html
The way that I did it for one of my apps is to just add them in the correct order. Add your tabbar controller to your window, then add the login controller over the top of the tab bar. Then show your window. The user won't see anything but your login controller. Once you login, you can just remove the login controller from view.
This way is probably best if you have information you need to hide until login. The other way is to only launch the login view only. On successful login, remove the login and add the tab bar controller. Either way is fine.
Presenting modally is probably the easiest, but requires a view in place before presenting. So if the data and view under the login controller isn't that sensitive, you could consider this option.
Another way would be using LoginViewControllerDelegate in your appDelegate.h file
In your .h
#import "yourLoginViewController"
//and add LoginViewControllerDelegate
Then in your .m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
yourLoginViewController *loginView = [[yourLoginViewController alloc] initWithNibName:#"yourLoginViewController" bundle:nil];
loginView.delegate = self;
[window addSubview:loginView.view];
[window makeKeyAndVisible];
}
//add this one
- (void)loginViewControllerDidFinish:(yourLoginViewController *)loginViewController {
[window addSubview:tabBarController.view];
}

Adding a UINavbarController & TabbarControlller to non root view

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];

removing window from modalviewcontroller

I launch a modal view controller and in its init I have the following code:
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
viewController = [[UIViewController alloc]init];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
I need the viewController for entering some data in it. How can I release the window and viewController so that I can go back to the viewController that launched the modal view controller? At this point, after I'm done doing what I need in the modal view, I am trying:
[viewController.view removeFromSuperview];
[window removeFromSuperview];
but just end up with the modal view's parent (the one that lanched the modal view) just frozen(it's not really frozen, it is just not user interactible because there are the window and view controller in front of it and the view controller doesn't have size and background
iOS app should only contain one UIWindow.
And you can easily present UIViewController with in viewController
[self presentModalViewController:navigationController animated:animated];
Then just call in that viewController to dismiss it:
[self dismissModalViewControllerAnimated:YES];

Navigation Controller and Table Views

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];
}