Search code examples
iosuiviewcontrollerswift2ios9transition

ViewController orientation change isn't animated


I'm trying to adjust some views when the iPhone changes it's orientation from portrait to landscape and vice versa. Everything works fine on iOS8 but unfortunately the changes aren't animated, but happen immediately, on iOS9. Here is the code that I have in a modal UIViewController presented via a custom transition:

override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.AllButUpsideDown
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return .Portrait
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

    let changeToPortrait = size.width < size.height
    coordinator.animateAlongsideTransition({ (context) -> Void in
        //show portrait
        if changeToPortrait {
            //do view changes...
        }

        //show landscape
        else {
            //undo view changes...
        }
    }) { (context) -> Void in
        print("done")
    }
}

If I print coordinator.isAnimated() it says false and therefore the coordinator.transitionDuration() is also 0.0.

What do I have to do to animate the transition changes?

Thanks for your help!


Solution

  • This behavior is likely because you set a custom UIWindow subclass to the window property of the AppDelegate inside the application:didFinishLaunchingWithOptions: method, as telomere mentioned in another answer.

    If you need to use a UIWindow subclass in iOS 9, implement a custom getter for the window property of the AppDelegate to maintain orientation change animations.

    Apple's documentation for UIApplicationDelegate's window property says:

    "...you must implement the getter method of this property and use it to create and return your custom window."

    Common practice is often to set the window property directly in application:didFinishLaunchingWithOptions:. Instead, in your AppDeleate, implement the custom getter like this (Thanks to Tomas Camin for the code, found here):

    Objective-C

    - (MyCustomWindow *)window
    {    
        static MyCustomWindow *customWindow = nil;
        if (!customWindow) customWindow = [[MyCustomWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        return customWindow;
    }
    

    Swift

    var customWindow: MyCustomWindow?    
    var window: UIWindow? {
        get {
            customWindow = customWindow ?? MyCustomWindow(frame: UIScreen.mainScreen().bounds)
            return customWindow
        }
        set { }
    }