I am working on my first iPhone app and making good progress. But there is one thing I just don't understand.
When my app starts it displays a UIView with some functionality on it. This works fine. One of the buttons on that screen is supposed to load a new view (HistoryViewController) which contains a navigation controller.
The problem is… whenever HistoryViewController is loaded the app crashes because there is no view. It's true because in the xib-File I can't connect the File's Owner's view to anything:
http://www.freeimagehosting.net/image.php?1a3caa8b8d.png
I definitely have a lack of knowledge somewhere but after hours of research I have not been able to solve this problem.
Any hints?
Thank you!
Normally you would either:
click on that bottom line (History Table View Controller, "HTVC") and in the inspector window specify a NIB Name - which means you would first have to make a new NIB.
or
doubleclick that bottom line (HTVC), so the 320x480 preview window pops up, and then drag in a UIView from the library.
Using the first method, you tell the view controller to dynamically load the NIB as the view to connect, and using the second method you do this for the view controller using IB. The view you drag in will then show up as a child of that bottom line (HTVC).
edit to actually load the nib file you created, do this to push the view controller:
UIViewController *controller = [[UIViewController alloc] autorelease];
[controller initWithNibName:#"nibfilename" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
substituting UIViewController for your own view controller class (if needed) and nibfilename with the filename of the nib (minus the extension!)
It's hard to tell what your problem is exactly, but I'll offer some advice.
When creating a navigation controller (or tab controller for that matter) in interface builder, its easy to not understand what is really happening, so my suggestion drop interface builder for a second and lets build it in code.
In general I really dislike building either UI Navigation Controller or tab view controller in interface builder, I really just rather build the views themselves and create the UINavigationController in code.
You have a view which shows the HistoryTableViewController which you want to be contained in a UINavigationController so the code to do this is:
- (void) showHistory
{
HistoryViewController *historyVC = [[HistoryViewController alloc] init];
// If you create historyviewcontroller in nib
// HistoryViewController *histroyVC [[HistoryViewController alloc] initWithNibName:#"myNib" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootController:histroyViewController];
[self presentModalViewContoller:navController animated:YES];
}
This will create a nav controller showing your history view controller as the root view controller. Can't be easier.
Related
So I'm building an app and I am running through a few ViewControllers that don't need to know about each other, so I start off switching through views like so...
// remove the previous view in order to load in the new view
NSArray *sViews = [self.view subviews];
[sViews makeObjectsPerformSelector:#selector(removeFromSuperview)];
// create the new view, in this case the user wishes to
BaseViewController *baseVC = [[BaseViewController alloc] initWithNibName:#"BaseViewController" bundle:[NSBundle mainBundle]];
self.baseViewController = baseVC;
[baseVC release];
// add the newly created view to the screen
[self.view insertSubview:baseViewController.view atIndex:0];
The above is the view controller that I want the navigation controller to reside in. So within the .m of this view controller I created a UINavigationController as a member variable and named it navController. I then tried implementing a UINavigationController using the code below.
UIViewController *control = [[BusinessDisplayViewController alloc] initWithNibName:#"BusinessDisplayViewController" bundle: nil];
navController = [[UINavigationController alloc] initWithRootViewController:control];
[self presentModalViewController:navController animated:YES];
The problem I'm running into is two fold. First, when the BusinessDisplayViewController (below) is loaded there is a 20 pixel or so gap between my mapView and tableView that isn't there when I was loading it using insertSubview: not sure why that would be. Second, once I'm in BusinessDisplayViewController.m I'm not sure how to access the navigationController created in BaseViewController. Could someone explain why my view would be effected, how I could access the navigationController or if I'm even going about this the right way.
UINavigationController is designed for use in one of three possible contexts on iPhone:
As the app's root view controller, with its view added as a subview of the app's window.
As one of the viewControllers of a UITabBarController.
Presented as a full screen view controller via presentModalViewController:animated:.
In your case, the UINavigationController has configured itself for presentation as a subview of the window. This is why you see the 20 pixel gap at the top. Since the window object underlaps the status bar, UINavigationController offsets the position of its navigation bar by 20 pixels (or more, if you're on a phone call).
The standard way to use UINavigationController as your root view controller is to construct it as a property of your app delegate in application:didFinishLaunchingWithOptions:, and add its view as a subview of the window. Then within any view controller you push onto your navigation stack, you can access the navigation controller object using self.navigationController.
Usually, you want your UINavigationController to be at the root level, Is there a specific reason for having your app setup this way? To answer your question though, you can access the variable by setting a property for it, then using the dot notation: baseVC.navController.
For the 20 pixel space problem, post your BaseViewController view related code. It is probably a bounds vs frame issue.
I have a view which contains a UIButton. When this is clicked, it calls a method that loads another NIB. Now, normally, that nib would load a view onto the stack, and everything would be fine. But, I am trying to load a Navigation Controller (so that I can have table views that are multiple levels deep), and all I get it errors.
What is the proper method for loading a Navigation Controller and putting it on the top of the stack?
As the other poster said you should create your Nav controller in your AppDelegate. If you are adding a new UIView to the stack like presentModalViewController you want to create the UIView then add the Nav Controller to it. If you don't want nav controller on that screen but the next just use the navController.hidden property I think it is.
To add the nav controller to the view do this:
NoticesView *noticesScreen = [[[NoticesView alloc] init] autorelease];
noticesScreen.delegate = self;
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:notices_screen] autorelease];
[self presentModalViewController:navController animated:YES];
Hope that helps towards your question. Still trying to find out exactly what your doing
Create the navigation controller in the app delegate. Push your mapview onto the stack as the first view. Push your tableview onto the stack as the second. If you started with a view-based app template, you won't have a navigationcontroller instantiated at all. (Been there done that) the easiest way out of this is to use xCode to make a navigation based applcation and then copy the code out of that. If you do already have a navigation controller, then just push the view controllers as above.
In my application which is based on a tabbar view controller with many uinavigationviewcontrollers for each tabbar items, I want to present at some point (at application launch) with a call to presentModalViewController that contains a uinavigationcontroller as a root so the user can do a few things... when he or she is finished, the Done button at the top right corner can be tapped to dismiss the modal view controller and then return to the base tabbar view.... How can I do that with Interface Builder ?
In XCode, create a new View XIB file and open it in Interface Builder. In this xib file, delete the View and drag a UINavigationController into it's place.
Then, in your view controller code, something like
UINavigationController *controller = [[UINavigationController alloc] initWithNibName:#"ModalViewController" bundle:nil];
[self presentModalViewController:controller animated:YES];
[controller release];
Will load your XIB and present it.
Hope this helps, any other questions don't hesitate to comment on this answer!
S
I would like to show a Navigation Controller after clicking a button. Every tutorial assumes the navigation controller will be the first screen so it links it to the App Delegate, but App delegate only appears at MainWindow.xib.
How do you guys add a navigation controller to a view different than the MainWindow?
Thanks!
Here is some sample code to expand on Roger's answer. The following method is linked to some user interaction on the current view controller (to compose an email for example). This will give the compose view the navigation bar across the top instead of coding buttons inside your custom view.
-(void) composeButtonPushed: (id) sender {
ComposeViewController *controller = [[ComposeViewController alloc] initWithNibName:#"ComposeView" bundle:nil];
UINavigationController *composeNavController = [[UINavigationController alloc] initWithRootViewController:controller];
[self presentModalViewController:composeNavController animated:NO];
}
UINavigationController is to navigate a heirarchy of views with UIViewControllers. If you don't have a root UIViewController, it won't work (and doesn;t make sense). If you do have a UIViewController, you simply send a - (id)initWithRootViewController:(UIViewController *)rootViewController init message to a new navigation controller passing in your UIViewController.
I think I've found the cause: Document Info window in IB has a warning: "'Selected Navigation Controller (Second)' has nib name property set to 'SecondView.nib', but this view controller is not intended to have its view set in this manner."
Bummer.
I've built nib in Interface Builder that has UITabBarController at top level and switches between UINavigationControllers.
It works fine when everything is in a single nib file, but I'd like to use separate nib files for UINavigationControllers.
Starting with Apple's TabBar template, if I just change class of SecondView to UINavigationController, it all breaks:
and all I get is this:
// imgur has lost the image, sorry //
Is it possible to have separate file for UINavigationController without programmatically setting everything?
I would like TabBarController to handle loading and unloading of nibs.
Simply swap the UINavigationController with the FirstViewController.
So the hierarchy should be like this:
Tab bar controller
-----Tab bar
-----Navigation Controller
----------First View Controller
---------------Navigation Item
----------Tab bar item (First)
-----Navigation Controller
----------Second View Controller
---------------Navigation Item
----------Tab bar item (Second)
You set the nib of First View Controller in the inspector to the nib file containing the actual view objects (Since you are trying to split them into separate files, which is a good thing).
You have one tab, that tab has a navigation controller which loads First View Controller as its root view.
Done.
I haven't tried setting up UINavigationController via IB. I have multiple screens, each is stored in separate xib and there's a corresponding class that extends UIViewController. In applicationDidFinishLaunching I initialize UIViewControllers using xib's but then manually create UINavigationController, add navigation controller's view to window and push first view to navigation controller.
Not sure if that helps.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
navigationController = [[UINavigationController alloc] init];
FirstViewController * viewController = [[FirstViewController alloc]
initWithNibName:#"FirstView"
bundle:nil];
[navigationController pushViewController:viewController animated:NO];
[viewController release];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
}
Above FirstViewController extends UIViewController, in IB you create your view then set File's owner class to your class (e.g. here FirstViewController) and connect the File's owner view to the UIView's view.
I believe you are looking for something like this. You would replace "whatever" with the name of you second nib file.
newNavController = [[UINavigationController alloc] initWithNibName:#"whatever" bundle:[NSBundle mainBundle]];
First, it looks like you have your UITabBarItems under the navigation controllers instead of directly under the UITabBarController. That may be part of your problem.
Second, when you add a UITabBarController in IB and and click on its icon in your list of top-level objects (your first screenshot), the attributes inspector will allow you to change the type of view controller for each of the tabs. Using this, you can change them all to navigation controllers, if you wish. Also, since you wanted to load custom views and view controllers from other nibs, if you look at the "View Controller" section at the bottom of the attributes inspector, you can select a nib from your project to load the view from. Assuming that nib's "File's Owner" is set to your UINavigationController subclass, it should all work fine.
All of this without a large amount of coding work, either. Let me know if you'd like screenshots for what I'm talking about in case you can't find these panels.
I found the same warning.I have kept all view controller in separate xib files. I got rid off it by removing .nib name and keeping it empty.