Troubles with iPhone UINavigationController (UINavigationBar in wrong place) - iphone

I'm in the process of making some adjustments to an app, including changing to a navigation-based interface. As part of that change I've written a view controller that contains a UINavigationController. The problem is, for some strange reason the UINavigationBar and UIToolbar managed by the UINavigationController are displaced 20px down from where they should be. I've managed to produce the following example that demonstrates the issue:
// MyAppDelegate.m
#implementation MyAppDelegate
#synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.frame = [[UIScreen mainScreen] applicationFrame];
[self.window makeKeyAndVisible];
TestController* tc = [TestController new];
[self.window addSubview:tc.view];
return YES;
}
#end
// TestController.m
#implementation TestController
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectZero];
UINavigationController* navController = [UINavigationController new];
navController.view.backgroundColor = [UIColor blueColor];
[navController setToolbarHidden:NO animated:NO];
[self.view addSubview:navController.view];
}
#end
This produces the following result on my machine:
As you can see, the controls are 20px down from where I'd expect them to be. I've tried just about everything I can think of (various combinations of wantsFullScreenLayout, autoresizesSubviews, etc) with no positive effect. This also has nothing to do with programatically messing with the statusbar (as seems to be the case in most other examples of this I have come across), since I do not at any point mess with the statusbar. This occurs with or without a root view controller in the navigation controller - if there is one, it's contents are shifted 20px down too (so they actually are in the right place relative to the navigation bar and toolbar).
Any help much appreciated!
EDIT: After a bit of investigation, it seems that removing the line self.window.frame = [[UIScreen mainScreen] applicationFrame]; seems to correct the positioning of the navigation bar and toolbar and content. That said, now some other views in the application are in the wrong place (up underneath the statusbar). My understanding is that line is generally recommended to ensure that the window is the correct size?

As mentioned in my edit, removing the line self.window.frame = [[UIScreen mainScreen] applicationFrame]; seems to have corrected 95% of my problems. I've managed to fudge an approach to fix the other 5% by using the same background colour for my window and the remaining views having issues, but I can't say I'm thrilled with this solution - I shouldn't have to do that.
I'll keep experimenting, and if I find a better result will certainly post an edit here.

UINavigationController does not play nicely with being used as a subview; as you've noticed, it will often leave room for the status bar even when it is not actually under the status bar. If you're not trying to write your own container view controller, you should rework your code to not be adding a view controller's view as a subview at all.
That said, I've had luck fixing it by setting wantsFullScreenLayout to NO on the UINavigationController, which will make it not leave space for the status bar. You would, of course, want to do this just after allocating it, before loadView gets triggered.

Related

Add a 'global' UIView to an App with StoryBoard

Is there a way to create a global UIView as background with the use of a StoryBoard?
I am updating my App, and making iOS 5 as the minimum so I can use ARC and also StoryBoards.
However, in my App I used a MainView.xib which I loaded as my rootviewcontroller, and any subsequent view was transparent so the background (and a button/copyright notice) were always visible.
I don't seem to be able to figure out how to do this. I can add the Subview to the rootview controller in the AppDelegate, but as soon as I seque to the next view it is gone.
Any suggestions how this can be done?
One way you can do this by adding an image view as a subview of the window itself, and making the backgrounds of all the view controllers clear.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIImageView *iv = [[UIImageView alloc] initWithFrame:self.window.frame];
iv.image = [UIImage imageNamed:#"BlueGreenGradient.tiff"];
[self.window addSubview:iv];
return YES;
}

StatusBar and RootViewController on iOS 6

My app has been running fine for a couple years, but there have been several hiccups with the release of iOS 6 and one of them is a problem with StatusBar orientation.
My app works in either Landscape orientation, but touches were vertically off by the width of the status bar in one of the two orientations. Intuitively, it seemed that even though the status bar image was being relocated properly during rotation, the LOGICAL position of the status bar was not changing -- and thus consuming touches on the wrong side of the screen.
In my Info.plist file "UIStatusBarHidden" was set to FALSE. In my App Delegate's "didFinishLaunchingWithOptions" function I created my own custom ViewController and set it as the RootViewController for the Window. Even though this worked prior to iOS 6, I believe it is at this point that the StatusBar did not "transfer" to the new RootViewController.
I theorized that prior to iOS 6 my code worked because orientation changes got propagated to the OLD RootViewController and caused orientation to work as expected. Since iOS 6 no longer propagates orientation beyond the NEW RootViewController, the OLD controller (which "logically" contained the StatusBar) never got updated.
Note: my app does not have a .XIB file and does not explicitly create a RootViewController until this point. But I think a default one was created for me behind the scenes anyhow.
My "solution" was to set "UIStatusBarHidden" to TRUE in the Info.plist file and manually set it to FALSE in code at a point AFTER I've set my custom RootViewController. This seems to work, but I may have addressed the symptom instead of the actual problem.
I'm also worried about side-effects because other things besides StatusBar could still be logically tied to that old/implicit RootViewController and they aren't getting "transferred" to the new one either.
Does anyone have similar experience with StatusBar and/or RootViewController? Is this approach ok or should I leave the default/implicit RootViewController in place and somehow add my ViewController to it as a child? That didn't seem to work when I first wrote the code two years ago, which lead to my current implementation.
Below are the highlights of the code in questions. Thanks in advance for the advice.
-BT
// ******** Info.plist value *********
<key>UIStatusBarHidden</key>
<true/>
// ******** App Delegate **********
- (BOOL)application : (UIApplication *)application didFinishLaunchingWithOptions : (NSDictionary *)launchOptions
{
CGRect rect = [[UIScreen mainScreen] applicationFrame];
rect.origin.x = 0; rect.origin.y = 0;
self.window = [[[UIWindow alloc] initWithFrame:rect] autorelease];
self.gameViewController = [[[GameViewController alloc]init] autorelease];
self.gameView = [[[GameView alloc] initWithFrame:rect] autorelease];
[self.gameViewController.view addSubview : self.gameView];
[self.window setRootViewController:self.gameViewController];
// Setting it now attaches it to our actual RootViewController instead of the
// "phantom" controller created under the hood?
[UIApplication sharedApplication].statusBarHidden = NO;
// ...
}

iPhone View Cutting Off

The view is created in interface builder, and is strangely cutting off at the bottom, and help or suggestions, is appreciated.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
Edit: I don't actually have a nib for the view controller, but instead a main window nib and a nib for two different views which are different themes.
Also if I use:
self.window.rootViewController = self.viewController;
it does not happen, but sadly this will crash in iOS 3.2 or below.
I experience the same problem, what I do is translating view 20 pixels down in ViewDidLoad then everything works fine. The problem surely is related to the statur bar but I do not know a solution other than this workaround.
To translate the view use this:
self.view.transform = CGAffineTransformMakeTranslation( 0, 20 );
In interface builder you need to check the dimensions of the view. You will see that it is too short (your height is probably set to 440, but it should be 460, or 480 if you don't have the status bar). This is probably why it appears to be cutting off.
Try enabling a simulated status bar in IB.

Problem with getting a modalViewController to appear

I've been fighting with this for hours. I've searched around everywhere and just can't seem to find the solution to my problem. I'm pretty sure I'm just lacking some key concepts here.
My AppDelegate (didFinishLaunching) basically sets up my window and invokes RootViewController:
// create our window
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setBackgroundColor:[UIColor blackColor]];
// create our rootviewcontroller
RootViewController *controller = [[RootViewController alloc] init];
// add our rootviewcontroller's view to our window
[window addSubview:controller.view];
// controller is now owned by window's view
[controller release];
// show us to the world
[window makeKeyAndVisible];
When I add controller.view as window's subview, my understanding is that RootVC's loadView will automatically get called.
In RootVC loadView, I create a tabBarController, each tab having a navigationController and it's own viewController. All that is working fine.
In RootVC viewDidLoad, I'm checking to see if this is the first time a user is running this app, and if so, I want to throw up a modal welcome screen. This is the part I'm having trouble with.
I'd like to keep as much code out of the RootVC's viewDidLoad method, and ideally would be able to accomplish what I want with this:
WelcomeViewController *welcome = [[WelcomeViewController alloc] init];
[self presentModalViewController:welcome animated:true];
[welcome release];
Obviously this isn't working. WelcomeVC's loadView hasn't been run yet because I haven't explicitly set it's view property. I've played around with a bunch of different solutions (welcome.view - [[UIView....], using WelcomeVC's init method to set self.view) but I just can't seem to get that modal to pop up.
How should I accomplish what I'm looking for? What are the best practices, and what's the best solution to keep my code tight and tidy?
I'm stuck, so hopefully your solution will allow me to continue developing my app!
Although the problem is not so simple, the solution is. You have to wait until the main view appears. So check the condition and present your modal view in viewDidAppear method, not in viewDidLoad method.

Why does an UIView in iOS/ appear too high up?

I'm relatively new to iOS programming. I have made a few basic apps before, and I'm getting back into it once again.
A problem I had a while back, and now is coming to haunt me is this.
When I create a new UIViewController subclass, myViewController (with xib) and add this code to get the add the view to the window, the contents always appear too high up, by the same width as the default/recommended left/right margin.
The code to add the view to the window is this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
MyViewController *aViewController = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
UIView *controllersView = [myViewController view];
[window addSubview:controllersView];
[window makeKeyAndVisible];
return YES;
}
For example, if I change the background colour of the view, I get a white strip at the bottom of the page when running in the simulator.
Any ideas?
Thanks
I don't think the problem is in that code. Although I guess you've done this already, it is probably a good idea to double check the .xib file. It may have an offset set in its position properties.
Also, it may be caused by the status bar not being set correctly. If you want to hide it, you can add an entry (UIStatusBarHidden -> true) in the info.plist file to set it to be hidden.
Either way check the dimensions of the .xib are the expected ones. And bear in mind the size of the status bar; the dimensions of the .xib file are different depending on whether the status bar is shown or not.