I have a few navigation controllers that are set up in a NIB under a tab controller. I'm trying to set up the same logo in the top view controller of each navigationcontroller.
In the first view controller that appears, I have this code in viewDidLoad:
self.navigationItem.titleView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"green-noback-logo-only.png"]] autorelease];
This works (well, almost, I'll have to resize the image) and replaces the text set up in the NIB with my logo image.
However, this exact same code doesn't work in either of the other two view controllers. Instead, any text I've set up for the title in the NIB shows. I've tried putting that code in initWithCoder, viewDidLoad, viewDidAppear and viewWillAppear and it does nothing. I'm explicitly setting leftBarButtonItem to nil, although I'm guessing it was nil to begin with. I have also already checked that self.navigationItem is not nil in any of the places where I'm trying to set the titleView.
Any idea what would be special about the other two controllers that would prevent them from having a titleView set? Otherwise, does someone have a more foolproof way to set titleView?
try setting the image view to self.navigationController.navigationItem instead of self.navigationItem.
tl;dr: I screwed up initWithCoder:.
A good wallbanger for a beginner. Following Paul N's answer, I discovered that self.navigationController == nil in the two broken view controllers. It took me another few hours of head-desking to figure out the rest.
All three top level view controllers were subclasses of UITableViewController. However, only two of them were using grouped style. I was overriding initWithCoder: to use initWithStyle: inside the two non-working table view controllers. This threw away the connection to the navigation controller stored in the NIB. I originally did this because I couldn't figure out how to set grouped style on those inside the NIB (suggested by another answer here).
Serves me right for subclassing in such a rotten fashion, I guess.
Anyway, the solution was to fix the initWithCoder: implementation to call [super initWithCoder:coder] as usual and set up the table view style in the NIB. I did this by dragging a table view under that view controller, setting the datasource, setting the delegate, and setting it to grouped style. (This is how table view controllers are set up in the NIB by default.)
Related
I can't believe I am stuck on this but here goes.
I have a viewController which I am trying to add to another viewController via the addsubview property (basic as) however I am not doing viewController.view but viewController.myView1.
I basically have 2 root views on the xib (both with outlets) however I don't want to wire up the view property of the xib because I want to choose which view to show.
I can't get it to appear! Is the view property some sort of special hook?
I can't see why addsubview:mysubview should not work?
Some examples seem to use 2 different xib's but that seems a overkill
Firstly, Apple say a viewcontroller should be used for a whole screen full of views - (but I guess iPad container views are different).
I guess you're wanting to only use one of the viewcontrollers at once. In which case you shouldn't be using subview - just create the viewcontroller programmatically, create the view, assign the view to the viewcontroller's view property and then add the viewcontroller to the window or navigation bar.
and, in your viewcontroller:
self = [super initWithNibName:nibOne bundle:nil];
might be what you want - it allows you to use multiple nibs with a single viewcontroller.
Can you NSLog your viewController.myView1 before add it as a subview? Is it nil or not?
If it's nil, try to add this line before your addSubview: method:
[viewController view];
Note: The viewController I am talking about is the same viewController which have two root views view and myView1.
Your code should be good as this is fairly simple and I do it all the time.
Just make sure your outlets are wired properly and that you are synthesizing them and that they are public in your header.
I have a Custom TabViewController that adds subviews to the current view depending on what UITabBarItem is selected. For the different subviews I have simulated a Navigation Bar and a Tab Bar so that the sub views match the format when they are displayed. The one sub view, which contains a UILabel, displays fine however the sub view with the UITableView overlaps the UITabBar. However in the Interface Builder I have sized the UITableView to not cut off the UITabBar.
Adding the subview in the TabViewController
[self.view addSubview:subViewController.view];
You haven't provided enough information to be sure, but I think you are adding the table view to the wrong view. Assuming that self is your UITabBarController subclass, you are adding the custom view in the view that covers the entire screen, including the tab bar.
Instead, you should be adding the custom views to the selected view controller's view:
[self.selectedViewController.view addSubview:subViewController.view];
This will limit the stuff you are adding to the tab bar controller's content area, and won't overlap the tab bar.
I'm not sure what you are trying to accomplish with this approach, though: it seems like it would make more sense to add subViewController to the set of view controllers that the UITabBarController manages, rather than messing around with the view hierarchy.
Also, there is nothing inherently wrong with loading views from a nib and then manipulating them in code. "Mixing styles" is not a problem.
As Legolas stated, it seems like you are mixing styles here. Given that it sounds like you need to push it from the code, you could try full instantiation of the object from the code, for example:
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(x, y, width, height)];
table.delegate = self; //or whatever the delegate is
table.dataSource = self; //or wherever the datasource is
...then add it to whatever view you need to.
If that all fails, double check your nib and make sure you have the proper options set for whether a tab bar is being shown, nav bar, etc, as that will effect the size.
Here's what I have:
A MainWindow.xib file configured with one UIViewController (subclassed to RootViewController). This nib gets loaded at application launch.
RootViewController has two ivars, a custom subclass of UIViewController and a UINavigationController. Both of these are loaded from nibs.
When the application launches both ivars are initialized from their respective nibs, and then the UIViewController.view is added as a subview of RootViewController.view.
Inside UIViewController's view I have a control that triggers an animated swap of UIViewController and UINavigationController. This is where the problem comes in. The swap animates, but the UINavigationController's views are not properly displayed. I get a Navigation Bar with no title, and nothing else.
The UINavigationController nib and underlying functionality have been tested in a stand alone project, but there was no RootViewController.
So, my question is, can I even do this? I've successfully swapped other view controllers like this, but never a UINavigationController. I've seen some documentation that leads me to believe this might be a fools errand, but I haven't convinced myself of that yet.
Solution (Kinda):
I found a solution (workaround? hack?), but it leads to some more questions. I nixed using a Nib for the UINavigationController. Instead, I loaded my UINavigationController's rootViewController from a Nib and then created the UINavigationController programmatically with initWithRootViewController:.
NavRootViewController *navRoot = [[NavRootViewController alloc] initWithNibName:#"NavRootViewController" bundle:nil];
navigationController = [[UINavigationController alloc] initWithRootViewController:navRoot];
[navRoot release];
This works as I expect. Which leads me to the conclusion that the rootViewController property of the UINavigationController wasn't being set properly when I loaded navigationController from a Nib. And the question is, why? Should it?
Also, when you see something like this happening in one case, but not another, it can be beneficial to either create a subclass and make your nib point at that subclass, or if you already have a subclass use that.
In the subclass, override all the various init:, initWithNibName:bundle:, viewDidLoad:, viewWillAppear:, viewDidAppear: and any other appropriate methods, and in those override, just NSLog("") something about which method it is (with param values perhaps) and call the super implementation.
This will give you an observable "track" of which methods are called in which order, and you can set a breakpoint to see where that call comes from.
This will give you enough information to find missing method calls, and then you can pursue the correct problem either here, or through filing a radar or ...
In some cases, viewDidLoad and viewDidAppear or awakeFromNib may need to be called each time you add the UINavigationController back into the stack of UIViewControllers. It seems that when the typical code executes out of your AppDelegate, that the Window, or something behind the scenes is doing something special for UINavigationController that presentModalViewController doesn't do.
I think you may have missed a conceptual point.
A UINavigationController controls view controllers instead of views. It controls when and where view controllers themselves are loaded. The views themselves are loaded only as a side effect of the pushing and popping of their respective controllers.
Therefore, putting a navigation controller inside of a view controller seldom makes much sense.
If I understand what you are trying to do correctly, you should have the RootController actually set as the rootController property of the UINavigationController (yes the nomenclature is extremely confusing.) Then when your swap event occurs, you should have the navigation controller push the next view. The RootController view will disappear to replaced by the other. then you can repeat the process for an arbitrary number of view controllers.
Only in the case of a tabbar would you want a navigation controller to be a property of a view controller. Even then it should be at the top the tab's hierarchy.
I'm having a problem getting my view to be sized properly when created via -loadView. It seems that my view frame is always (0, 0, 320, 460), even when the view/controller is nested inside a UINavigationController and/or UITabBarController. Is there a way to detect programmatically when my view controller is nested within these items, so that I can set the proper frame? My loadView is just setting up a nested UIScrollView that should match exactly the visible size on the screen (460px is too tall when there is a tab bar and nav bar visible).
The reason I'm not hardcoding these values is that I would like this view controller to be reusable and work in all scenarios.
There are a few properties of in UIViewController that might be of interest here:
navigationController
tabBarController
If these are not nil you should be able to tell if you need to resize your view or not.
Do not layout your views in loadView: or viewDidload: without a nib. Do it in viewWillAppear:, the main view's frame is properly at that time.
MyController *myViewController = [[MyController alloc] initWithNibName:#"myView" bundle:nil];
The nib file myView.nib has 2 uiimageviews and 2 uilabels. When I first init myViewController, all the 4 subviews are set as 0x0.
The second time I dont get such a behavior.
The view object itself does not get created until it is referenced via self.view and loadView is called. It could be that the first time you try to inspect the view or do something with it this hasn't happened yet, and the second time could be after the system creates the view if you are adding it to another view or a navigation controller or something.
You probably forgot to hook up the view in your Nib file to the view property of MyController, and/or hooked up the subviews to the various IBOutlets of MyController.
Kevlar is absolutely right. You can force loading view and setting up all references with the following statement:
if (myViewController.view);
It does nothing except you'll get all subviews bound to outlets.