iPad app. I have a tabbar. One tab has a view controller with a view. In that view controller I add a uinavigationcontroller. If I start the app in portrait, everything works fine. However if the app starts in landscape, my navbar y position is 20 (instead of 0 which it should be). I can see the view behind the navbar. If I manually re-position (a bandaid) the uinavigationcontroller to -20 y, I get a host of sizing problems throughout the app. How can I fix this? (by the way, if i remove the status bar it sizes just fine in landscape)
Here is the code of my view that manages the navcontroller:
- (void)viewDidLoad
{
[super viewDidLoad];
self.topicsList = [[TopicsListVC alloc]initWithStyle:UITableViewStylePlain];
self.navController = [[UINavigationController alloc]initWithRootViewController:self.topicsList];
self.navController.view.frame = self.view.frame;
[self.view addSubview:self.navController.view];
Related
I am using UISplitViewController with UITabbarController as master view and navigation controller as detail view. Each of the tabs on the master view contain a navigation controller. When any of the tabs on the master view are selected, a view is pushed on the detail view navigation controller.
recentsviewController = [[RecentsViewController_ipad alloc]initWithNibName:#"RootViewController" bundle:nil];
recentsNav = [[UINavigationController alloc] initWithRootViewController:recentsviewController];
//similarly rootNav and favNav
NSArray* controllers = [NSArray arrayWithObjects:recentsNav,self.rootNav,favNav,nil];
self.tabbarController.viewControllers = controllers;
detailViewController=[[LoginViewController_ipad alloc]init];
detailNav=[[UINavigationController alloc]initWithRootViewController:detailViewController];
splitViewController =[[UISplitViewController alloc]init];
splitViewController.viewControllers=[NSArray arrayWithObjects:self.tabbarController,self.detailNav,nil];
splitViewController.delegate = self.detailViewController;
[self.window addSubview:splitViewController.view];
[self.window makeKeyAndVisible];
This seems to work fine. When app goes into portrait mode a 'Browse' button is added to the navigation bar. Clicking this button shows the hidden view along with the tabs perfectly fine. I can switch between the tabs and work on the views displayed in the popover. When tapped on other than popover area the popover is dismissed as expected.
The two things that are not working are
The popover has to show up on its own each time app switches to portrait mode without the user having to select the button added to nav bar
On some occasions I need to dismiss the popover programatically.
I have tried foll code :
- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController: (UIPopoverController*)pc {
barButtonItem.title = #"Browse";
[[self navigationItem] setLeftBarButtonItem:barButtonItem];
self.appDelegate.rootPopoverButtonItem = barButtonItem;
self.appDelegate.splitViewPopover = pc;
[self.appDelegate.splitViewPopover presentPopoverFromBarButtonItem:self.appDelegate.rootPopoverButtonItem permittedArrowDirections:UIPopoverArrowDirectionUp animated:NO];
}
This adds a black translucent popover each time the orientation changes. How do I make it show what the browse button shows when it is clicked?
The usual dismissPopvoerAnimated does not seem to work here.
Any help is appreciated.
Using performSelector:withObject:afterDelay: fixed the issue
I was under the impression that a UINavigationController's navigation bar would always push down the child view's height, such that the child view's origin was at the bottom of the title bar.
But when I present a view controller like this ...
MyViewController *viewController = [[MyViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
viewController.title = #"My View Controller";
viewController.navigationItem.prompt = #"My Prompt";
viewController.delegate = self;
[self presentModalViewController:navigationController animated:YES];
[navigationController release]; [viewController release];
... and then check self.view.frame.size.height with an NSLog in viewDidLoad, it reports that my view is 460px high. Shouldn't it subtracting the height of my title & prompt?
So, as requested:
When you call viewDidLoad the view controller hasn't been pushed onto the screen yet. So when you get the frame size from within that method it will report its' default (typically, 320x480 for an iPhone app).
The view then autoresizes to take into account the navigation bar. So when you check the frame size in viewWillAppear it will now be correct. Typically this isn't a problem for iPhone apps. For iPad apps, where you have multiple orientations, it can be a bit of a pain!
There are a few exceptions to this - for example, when using NIBs.
Probably you are referring to the wrong self here.
When self refers to the MyViewController instance you will probably have an height of 460 - 44 pixels (standard UIToolbar height), but if self refers to a parent view controller (e.g. the navigation view controller itself) you'll see the standard view height (e.g. 460px).
You can check this by calling self.view.frame.size.height inside the instance of MyViewController, e.g. when the view has finished loading (viewWillAppear: method), and so has already been resized by its navigation controller.
If you call self.view.frame.size.height from the viewDidLoad method, the view probably has still not been resized by its parent controller.
Please try again and let me know if this fixes your problem.
I have a tab bar application and when I display a modal view controller, the content screen is offset by about 20 pixels to the top and left. It looks like this:
I'm presenting this view from the child view controller (detail view) of navigation controller (main view) of the tabview.
When I show the view, I'm hiding the tab bar and navigation bar but status bar is kept visible. Adjusting the view to be centered (through Interface Builder's Simulated Interface Elements->View Mode : Center) and changing the view's frame after a call to 'viewDidLoad' in the controller doesn't seem to shift it.
- (void)viewDidLoad {
// this still doesn't cause it to shift
self.view.frame = CGRectMake(0, 20, 320, 460);
}
What's the way to adjust this so that the content area is shown correctly?
I launch the child view like this:
[detailController presentModalViewController:tvc animated:NO];
The app's view controller hierarchy:
Tab view with two child navigation controllers are created in the app delegate and the nav controllers added to the TabBar's view controllers:
tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = [NSArray arrayWithObjects:tab1ViewController,
tab2ViewController, nil];
[window addSubview:tabBarController.view];
Each view controllers of the tab is created as a NavigationController with 1 view controller:
// MainViewController inherits from UIViewController
[MainViewController *viewController = [[MainViewController alloc] initWithNib..];
tab1ViewController.viewControllers = [NSArray arrayWithObject:viewController];
A detail view controller is launched with 'pushViewController' as a result of some action on tab1ViewController :
DetailController *detailController = [[DetailController alloc]
initWithNibName:#"DetailView"
bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:detailController animated:YES];
[detailController release];
It's from the detailController that I'm trying to launch the problem controller.
Some things to check right off: is "viewDidLoad" actually getting called?
If so, what is self.view.frame set to after the assignment?
Put an NSLog at the end that prints out the x, y, width, height, and see what's there.
Also, since the trouble vc is modal, it will occupy the entire screen.
"On iPhone and iPod touch devices, the view of modalViewController is always presented full screen."
HTH,
Mike
I have the starter point of my application this window (white background):
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
mainScreen = [[MainScreenController alloc] initWithNibName:#"MainScreenController" bundle:[NSBundle mainBundle]];
// add it to the main window
[window addSubview:[mainScreen view]];
// show view
[window makeKeyAndVisible];
NSLog(#"started");
return YES;
}
And MainScreenController is an UIViewController with (blackBackground) created by the Interface Builder.
The application executes perfectly but the first time, the black view is moved up like the height of the status iphone pannel (leaving white rectangle at the bottom).
If I rotate the iPhone twice, the view is perfectly positioned in the right place, filling all the screen with the black background.
Any idea?
Thanks!
Check your MainScreenController settings in IB. You should select a simulated status bar element (cmd-1) so that the view is positioned below the status bar initially.
EDIT - Why are you calling the initWithNibName in your delegate here? Most of the app templates I've used had the main view nib initialized by the OS and you use IB and set an IBOutlet in the main VC interface. You probably have an initial frame origin of {0,0} after calling initWithNibName. Add these lines after your initWithNibName call to verify this:
NSLog(#"mainscreen frame=%#", NSStringFromCGRect(mainscreen.view.frame));
CGRect frame = mainscreen.view.frame;
frame.origin.y = 20; // move below status bar
mainscreen.view.frame = frame;
My iphone application is showing strange behavior when rotating: a gap appears between the navigation title and content view inside a tab bar view (details on how to reproduce are below). I've created a tiny test case that exhibits the same problem: a custom root UIViewController, which creates and displays a UITabBarController programmatically, which has two tabs: 1) plain UIViewController, and 2) UINavigationController created programmatically with a single plain UIViewController content view.
The complete code for the application is in the root controller's viewDidLoad (every "*VC" class is a totally vanilla UIViewController subclass with XIB for user interface from XCode, with only the view background color changed to clearly identify each view, nothing else).
Here's the viewDidLoad code, and the shouldAutorotateToInterfaceOrientation code, this code is the entire application basically:
- (void)viewDidLoad {
[super viewDidLoad];
FirstVC *fvc = [[FirstVC alloc] initWithNibName:#"FirstVC" bundle:nil];
NavContentsVC *ncvc = [[NavContentsVC alloc] initWithNibName:#"NavContentsVC" bundle:nil];
UINavigationController *svc = [[UINavigationController alloc] initWithRootViewController:ncvc];
NSMutableArray *localControllersArray = [[NSMutableArray alloc] initWithCapacity:2];
[localControllersArray addObject:fvc];
[localControllersArray addObject:svc];
fvc.title = #"FirstVC-Title";
ncvc.title = #"NavContents-Title";
UITabBarController *tbc = [[UITabBarController alloc] init];
tbc.view.frame = CGRectMake(0, 0, 320, 460);
[tbc setViewControllers:localControllersArray];
[self.view addSubview:tbc.view];
[localControllersArray release];
[ncvc release];
[svc release];
[fvc release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Here's how to reproduce the problem:
1) start application
2) rotate device (happens in simulator, too) to landscape (UITabBar properly rotates)
3) click on tab 2
4) rotate device to portrait -- notice gap of root view controller's background color of about 10 pixels high beneath the Navigation title bar and the Navigation content view.
5) click tab 1
6) click tab 2
And the gap is gone! From my real application, I see that the gap remains during all VC push and pops while the NavigationController tab is active. Switching away to a different tab and back to the Nav tab clears up the gap.
What am I doing wrong? I'm running on SDK 3.1.3, this happens both on the simulator and on the device. Except for this particular sequence, everything seems to work fine. Help!
This problem occurs when you nest a UINavigationController within another UIViewController (in this case a UITabBarController). If you had the UINavigationController as the root view controller, then this problem wouldn't occur.
One solution may be to go in and alter the frame of the navigation bar (set the y origin from 0 to 20), but the documentation states explicitly not to do this. So to me, this is an indication that it isn't considered good UI to nest a UINavigationController - you shouldn't be doing it.
Please let me know what you think - thanks. :)
A workaround works in some occasion:
After rotating, force a refresh of the NavigationBar and therefore the frame of its view is resized properly. Some code like this:
(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
// if _navigationController is showing
[_navigationController setNavigationBarHidden:YES];
[_navigationController setNavigationBarHidden:NO];
}