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.
Related
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.)
Is it possible to view the viewcontroller behind the displayed one? I have a viewcontroller with a scrollview, which has imageviews added as subviews and would like the view that presented this viewcontroller to be visible behind the presented view controller.
I have set all the views, the viewcontroller view too to have a clear color background, but still there is a black background. when I dismiss the viewcontroller, I see 2 layers being dismissed. one has alpha dropped, the other not.
Is there an easy way to make this effect possible?
Its not possible. When a new view controller is pushed or presented as modal view, the previous view controller will be removed from the display(may be UINavigationController/iOS hides it). The rule is only one view controller would be visible at a time. So you will see the color of your window(the black color you've mentioned) in the background.
What you could do is make a screenshot before displaying the other controller. and send this image to new controller to be displayed as background.
This will only work for static content, but you could do something like the curl display.
You can do this but the truth is what EmptyStack says.
You can use setFrame of the subView and add it on the viewController. Also use below method to set the index of the added View. By default currentView has Index 0.
[self.view insertSubview:myView atIndex:0];
or you can try below methods as per your logic
insertSubview:aboveSubview:
insertSubview:atIndex:
insertSubview:belowSubview:
addSubViews:
bringSubviewToFront:
removeFromSuperview:
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.
in an iPad application, I am displaying a modal view controller (through presentModalViewController) in a FormSheet style (so it's about 540 pixels wide and high), the root view controller displays fine (its frame's size is set to roughly (540, 540) and my code takes care of laying out the content properly).
However, when a push a view controller, its frame's size always has (768, 1024) which is wrong. I tried to set its frame explicitly like this:
DetailViewController* detailController = [[DetailViewController alloc] init];
detailController.view.frame = self.view.frame;
[self.navigationController pushViewController:detailController animated:YES];
Any ideas why it doesn't set the size properly?
well, layoutSubviews should be used if the actual frame of the view at runtime is needed. I ended up using that to lay the subviews inside the controller's view. (although I had to create a custom UIView subclass for controller's view)
Your approach looks right. Forgive my question, but have you debugged this with breakpoints and GDB?
You might try this from the console (cmd shift r):
print [[self view] frame]
and
print [[detailController view] frame]
print this before and after you call pushViewController:animated on the UINavigationController to see if its frame size changes from the pushViewController:animated method.
Another note, its hard to see a use case for pushing a view controller to a UINavigationController that would NOT consume the entire UINavigationController's views area. Every push onto the navigation controller represents a level deeper into some navigation (unlike UIView - addSubView).
http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
Update: This is why you are having problems:
The view is automatically resized to fit between the navigation bar and toolbar (if present) before it is displayed.
You will find that on apple's documentation on the link I provided. See pushViewController:animated:
View controllers are expected to manage an entire "screenful" of content. Only one view controller (not counting container controllers like UINavigationController) is active at any given moment. The only exception is UISplitViewController, which allows two view controllers to have content on the screen at once.
I want to duplicate this controller same functionality without using it, this is because tab bar controllers are not customizable at all (fixed size, toggleable state tabs, etc...).
I want a customized "tab bar" that contains whichever view I want. And also I need to push view controllers leaving this customized tab bar fixed in its position.
I´ve seen lots off apps that do this, and I was wondering if using different UIWindow objects (one for the custom tab bar and other one for the content) was the best approach.
Any advice or guidance on this?
Thanks in advance.
Definitely not UIWindows - in an iPhone app there should only ever be one UIWindow.
I'd make a UIViewController subclass that had your new navigation bar ui at the top and a UIView underneath it. This view would be used to contain all the views of the controllers you are going to push in it. The view would have clipsToBounds set to YES to make sure your other controllers views don't overlap your navigation bar etc.
It would also have an array to hold the list of controllers that are currently inside it.
Your controller would implement the pushViewController:animated: methods etc to allow you to add other view controllers to the stack - you would add the new controller to your array and would add it's view as a subview of your controller's view.
However, it's actually quite a lot of work to make this well - a navigation controller will release child controller views on low memory warnings, handle rotation, animating on/off views etc. Are you 100% sure that this is what you want to do?
I've used a very simple approach. I subclass UITabbarController and during the init:
// Custom TabBar View
//
self.tabBar.hidden = YES;
MyTabBarView *myTabBarView = [[MyTabBarView alloc] initWithFrame:CGRectMake(0, 1024-44, 768, 44) // it'a an iPad app
configuration:configuration]; // an array of dictionary representing the view controllers
[self.view addSubview:myTabBarView];
[bottomBarView release];
then I load some view controllers with:
aViewController.hidesBottomBarWhenPushed = YES;
From MyTabBarView instance I perform on the UITabBarViewController:
setSelectedIndex:
In this way I've a customizable full screen application without pains.