Search code examples
iosuiviewcontrollerios8autorotate

ViewController offset after device rotation in iOS8


I am experiencing an odd problem with legacy code running in iOS8. The code was originally written pre-iOS6, pre-storyboards (using nibs) and functioned without issue on iOS7. However, strange behavior began to occur when running on iOS8.

The app is set to run only in landscape (left or right). Therefore it should support autoRotation from landscape-left to landscape-right. The first problem was that the initial view controller was loaded in portrait and one side was cut off. This issue was addressed with the following code in the AppDelegate:

self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[self.window setFrame:[[UIScreen mainScreen] bounds]];

Changing the order of these calls allowed the view controller to load in its proper orientation and did not affect apps running in iOS7. However, now when the device is rotated 180 degrees I get the following results. See images...

Here is the app at initial load: enter image description here

And after a 180 degree rotation, I get this offset effect: enter image description here

Any ideas on how to address this issue? Again, everything is fine in iOS7 or previous. THanks!


Solution

  • I had a problem just like yours when iOS 8 first appeared, and it had nothing to do with the opening window-creation incantation! It has to do with your Info.plist. It is crucial that the first orientation listed in the Info.plist be an orientation that the root view controller actually permits.

    So, let's say your root view controller permits only landscape. Then you will get the problem you describe if your Info.plist looks like this:

    <key>UISupportedInterfaceOrientations</key>
    <array>
        <string>UIInterfaceOrientationPortrait</string>
        <string>UIInterfaceOrientationLandscapeLeft</string>
        <string>UIInterfaceOrientationLandscapeRight</string>
    </array>
    

    See the bug? Portrait comes first. No. If the root view controller permits only landscape, then one of the landscape orientations must come first.

    [You can actually see me experiencing the issue, then discovering and reporting the solution, here: https://stackoverflow.com/a/24467576/341994]


    Also, I have to wonder whether you might be doing anything else that upsets the rotation system. Note that the nature of rotation itself, including the coordinate system, what rotates, when it rotates, etc., has completely changed in iOS 8; this is probably the biggest single change in iOS 8. So if you have old code that makes under-the-hood assumptions about what rotation is (e.g. that it involves a transform), that code will now break. You do not show any of that in your question so I can't provide specifics about what you might be doing.


    Finally, just for the record, the correct minimal opening incantation is (this is Swift code but I'm sure you can translate):

    func application(application: UIApplication, 
        didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        self.window!.rootViewController = UIViewController() // or whatever it is
        self.window!.backgroundColor = UIColor.whiteColor()
        self.window!.makeKeyAndVisible()
        return true
    }