iOS 8 - Launching the application in Landscape mode - ios

My iPad application supports all the orientations and it worked fine in iOS 7 as well.
However in iOS 8, launching the application in Landscape mode made my login view draw the landscape view within a portrait frame.
After doing some analysis I found out that the application window does not take the correct orientation while launching in Landscape. Doing a rotation after that corrects the UI since it takes the correct orientation from that point onwards.
Would someone be able to guide me through this? Thanks in advance.

The issue seems to be the order of calls when you set up the window. You need to call makeKeyAndVisible before you assign the rootViewController. The following works:
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self.window makeKeyAndVisible];
self.window.rootViewController = self.myMainViewController;
But if you change the order to:
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.rootViewController = self.myMainViewController;
[self.window makeKeyAndVisible];
You get the behavior you are experiencing.

Thank you Dave Kammeyer for the workaround for this annoying iOS8 bug.
If you are working with storyboards you don't really have access to makeKeyAndVisible because UIApplication automatically wires everything together before calling AppDelegate. In this case, I just reset the rootViewControllerat the start of application:didFinishLaunchingWithOptions:
UIViewController* rootViewController = self.window.rootViewController;
self.window.rootViewController = nil;
self.window.rootViewController = rootViewController;
Afterwards the app starts in landscape without bugs.

I had the root view controller set up in the XIB, by having my navigation controller in the MainWindow.xib, and that navigation ctlr's root view controller the class of my actual root view controller. Thus it would find my root view controller automatically, instantiate it, and hook it op to the navigation controller, and that to the window.
But: apparently that is too early in the game, and causing trouble, when started in landscape mode.
So I broke the Window's connection to the root view controller (being the navigation controller) in the xib, and set the root view controller myself:
self.window.rootViewController = self.navigationController;
Effect is the same as the connection in the nib, but as it happens at a later point it time it is now okay.

The following code worked for me
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
application.statusBarOrientation = UIInterfaceOrientationPortrait;
// the rest of the method
}
Hope it will help !!!

Related

UIWindow in iOS8 doesn't rotate correctly

I need to load storyboard programmatically, in iOS7 the following code works:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // need to comment out in iOS8
self.window.backgroundColor = [UIColor cyanColor];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.window.rootViewController = [storyboard instantiateInitialViewController];
[self.window makeKeyAndVisible];
return YES;
}
But in iOS8 (XCode 6.1), the above code doesn't auto rotate correctly:
and
I need to comment out self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; to correct the auto rotation.
Any idea that first line makes what different?
Well, I find the answer from developer forum. Just remove the UIMainStoryboardFile key from app's information property list.
"Your application's information property list contains the UIMainStoryboardFile key but you are also manually creating a UIWindow with a storyboard loaded manually in your app delegate.
When the UIMainStoryboardFile key is present in the information property list, the system creates a UIWindow object with the initial view controller from the storyboard corresponding to the value of the UIMainStoryboardFile key prior to calling your app delegate. Your app delegate then repeats this process, determining which storyboard to load based on the screen size, and creating another UIWindow with the initial view controller from the storyboard.
The window created by the system, being the first window, receives orientation change notification first. Due to a change in iOS 8.1, the first window ends up blocking the second window (the one you created, the key window) from responding to the orientation change. From what I have discerned, this only happens if the first windows rootViewController's view is not loaded (the original window is never made visible). I'm clarifying the details with engineering and will log any needed bug reports myself.
The solution for your app is to remove the UIMainStoryboardFile and UIMainStoryboardFile~ipad keys from your app's information property list."

Changing UIWindow causes SVProgressHUD to not appear

I have 2 UIWindows that I use in my app. In AppDelegate, in the method didFinishLaunchingWithOptions: I simply have:
self.windowStartup = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.windowSplit = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
Then I set up self.windowSplit as a splitViewController and windowStartup with a xib as its rootViewController. If I load windowSplit from didFinishLaunchingWithOptions:, then SVProgressHUD works great, however if I load windowStartup in didFinishLaunchingWithOptions:, then call:
[self.windowSplit makeKeyAndVisible];
at a later time, SVProgressHUD won't work. Everything else is working as expected. My desire is go get SVProgressHUD working for the 2nd scenario, but also to find out if there something I am doing wrong that could impact on anything else.
For a little more info, the reason why I am taking this approach is that I want to use the standard split view controller, however I want to load the startup view first, without it just appearing over the top of the splitView on the iPad. After the user has set things up they can decide if they want the startup view to show initially.
Thanks in advance for any help!
Edit:
Here is my code for startup:
Startup *controller = [[Startup alloc] initWithNibName:#"Startup" bundle:nil];
self.windowStartup.rootViewController = controller;
[self.windowStartup makeKeyAndVisible];
It was a simple naming issue. I had issues with SVProgressHUD and ShareKit. Both were looking for the
.window
property of my appDelegate. I went back to the standard
UIWindow *window
and it works fine again.

AppDelegate window.rootViewController Property

I have a problem with my iOS app. It is based on storyboards. So to set the rootViewController property it should be enough to set the "Initial View Controller" property in Interface Builder and the MainInterface-Property in the project settings to the name of my storyboard. Still I always get the message "Application windows are expected to have a root view controller at the end of application launch".
I do several things in the applicationDidFinishLaunching section but even if everything except return YES; is commented out, I get the message.
How can I fix this warning? Or can I ignore it as everything works?
Thanks a lot.
Are you using an activity indicator in your app delegate or root view controller by chance? If so, it might be setting itself as the root. Move the display of the indicator to somewhere after your main views are set up.
Try this code :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
InitialViewController initial = [self.storyboard instantiateViewControllerWithIdentifier:#"STORYBOARDID"];
window.rootViewController = initial;
[window makeKeyAndVisible];
return YES;}

UIWindow's root view controller does not rotate to landscape at app launch

I am developing a xib-based landscape-only app. The app launches in landscape correctly. However, the view in my main ViewController is presented in portrait. That is, it is rotated 90 degrees so that the image appears cropped and does not take up the entire screen. If I use my interface to present a modal view controller then return to the main ViewController, the issue corrects itself (the view is presented in landscape). This problem did not occur under Xcode 4.2. It occurred after upgrading to Xcode 4.3, and the only code changes that were made were automatically implemented by Xcode when I upgraded the project settings.
Based on advice in other posts, I verified my Info.plist settings for Supported Interface Orientations and Initial Interface Orientation. I overrode the shouldAutorotateToInterfaceOrientation method for each of my view controllers to return YES only for landscape orientations. Also, I turned off auto resizing for the view, as I never want the size/orientation of the view to change.
Based on the ideas in this link [1], I suspected the problem is that the view is not receiving the call to change orientation at launch, possibly due to the removal of the MainWindow.xib concept, which appears to be replaced by the following Xcode-inserted code in AppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
I modified this method to generate a generic root view controller from which my ViewController class is presented, as shown in the code below:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
ViewController* myViewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.viewController = [[UIViewController alloc] init];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.viewController presentModalViewController:myViewController animated:NO];
return YES;
}
Voila! This solved my problem. However, to me it feels like a change at a fundamental level, which I don't want to make at this point in my development. What I intended to be my root view controller is now a modal view. Does anyone have another solution to this issue?
Thanks in advance!
I had this same issue: an app which was meant to be in Landscape that assumed the ViewController was always in Portrait. I made tons of changes to every aspect of the project and info.plist, including giving the main UIWindow a root-view controller which was landscape. It still didn't work. I eventually undid all the changes and just added the two lines noted below to my app delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
[_window addSubview:[_viewController view]];
glView = _viewController.glView;
// THIS FIXED ORIENTATION FOR ME IN IOS 6
_window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
// END
...my other setup code here...
}
Nothing else was necessary.
It appears that, for some reason, in iOS 6 the UIWindow root-view-controller setting is sometimes ignored in Interface Builder. I am sure my reasoning is wrong somewhere, but I thought this might well help prod someone in the direction of a fuller, more exhaustive answer.
In iOS 8, settings windows frame to the UIScreen is also necessary, as it won't get automatically updated.
self.window.frame = [UIScreen mainScreen].bounds;

Hiding the master view in a Split View Controller

I am new to iPad development (or iPhone for that matter :) ) and I am building an app with a Split View Controller.
The thing is the first screen should be a single screen. I want the user to write user/pass data to connect to a remote server, and there's not really anything to show in the master view.
I know I can return YES in the splitViewController:shouldHideViewController:inOrientation:, and that works fine for the first screen, but I'd like to get the two views when the user taps the login button and the credentials are validated.
I can put some condition in shouldHideViewController and that shows the two views in the second screen and only the detail in the first, but shouldHideViewController is only called if I rotate my iPad, not when I perform the segue.
Do you have any tips to do this? Should I change my UI approach to something else? Any suggestions are welcome.
starting from scratch is a good idea. You have more control over whats going on IMO.
At your starting point you want to add your LoginViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.loginController = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Later when the authentication process has finished you want to continue with SplitView, right?
- (void)continueWithSplitView {
UINavigationController *leftNav = [[UINavigationController alloc] initWithRootViewController:self.masterViewController];
UINavigationController *rightNav = [[UINavigationController alloc] initWithRootViewController:self.detailViewController];
self.splitViewController.viewControllers = [NSArray arrayWithObjects:leftNav, rightNav, nil];
self.view.window.rootViewController = self.splitViewController;
}
Notice that in both methods your desired viewController is set as the rootViewController property of UIWindow. This will automatically add the view of your controller as the top level view in UIWindow.
Furthermore make sure that you are following the MVC pattern e.g. a model object for your credentials organisation.

Resources