Search code examples
iosswiftscreenscreen-orientation

iOS 8 - UIWindow Orientation Is Always Portrait


I am updating an iOS 6 app to iOS 8 (iPad), and any new UIWindows that I create are always showing up in Portrait mode. The app originally supported both the Portrait and Landscape orientations but now will only support Landscape.

I've changed the supported orientations in the project file to Landscape Left and Landscape Right. The entire UI shows up in landscape, as expected, but when I create a new UIWindow, it shows up in portrait. The new UIWindow's frame matches the screen's frame exactly, so I can't imagine why/how it is showing up in portrait mode.

The following code is what I am using to create and show the new UIWindow, which acts as a modal:

var modalWindow:UIWindow = UIWindow(frame: self.view.window!.bounds)

modalWindow.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.66)
modalWindow.hidden = false
modalWindow.windowLevel = (UIWindowLevelStatusBar + 1)

modalWindow.addSubview(customView)    

modalWindow.makeKeyAndVisible()

I've been struggling with this for a few hours; shouldn't the UIWindow be in landscape mode by default since the app only supports the Landscape orientation?

I would greatly appreciate any advice on how to resolve this issue.

EDIT:

I just created a new test app that only supports Landscape Left and Landscape Right, and the issue occurs there as well. Is this a bug? I can't seem to understand why the UIWindow would think the app is in Portrait mode when it's in Landscape mode.


Solution

  • EDIT (July 2, 2015)

    This answer breaks in iOS 8.3+ and possibly previous versions of iOS 8. I DO NOT recommend that anyone uses it, especially since it is not guaranteed to work in future iOS versions.

    My new solution uses the standard presentViewController method of a UIViewController. I initialize a UIViewController, add my custom modal View as a subview of the UIViewController, and then position the modal View using constraints. Works like a charm!


    Original Answer

    I left this for a while but decided to come back to it today. I ended up rotating the modal window -90 degrees since it is automatically rotated 90 degrees to be displayed in portrait. I also added a small calculation for the modal window's width and height to support both iOS 7 and iOS 8. Here is my new code:

    // Get the screen size
    var screenSize:CGSize = UIScreen.mainScreen().bounds.size
    
    // Use the larger value of the width and the height since the width should be larger in Landscape
    // This is needed to support iOS 7 since iOS 8 changed how the screen bounds are calculated
    var widthToUse:CGFloat = (screenSize.width > screenSize.height) ? screenSize.width : screenSize.height
    
    // Use the remaining value (width or height) as the height
    var heightToUse:CGFloat = (widthToUse == screenSize.width ? screenSize.height : screenSize.width)
    
    // Create a new modal window, which will take up the entire space of the screen
    var modalWindow:UIWindow = UIWindow(frame: CGRect(x: 0, y: 0, width: widthToUse, height: heightToUse))
    
    modalWindow.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.66)
    modalWindow.hidden = false
    modalWindow.windowLevel = (UIWindowLevelStatusBar + 1)
    
    modalWindow.addSubview(customView)    
    
    // Create a -90 degree transform since the modal is always displayed in portrait for some reason
    var newTransform:CGAffineTransform = CGAffineTransformMakeRotation(CGFloat(-M_PI / 2))
    
    // Set the transform on the modal window
    modalWindow.transform = newTransform
    
    // Set the X and Y position of the modal window to 0
    modalWindow.frame.origin.x = 0
    modalWindow.frame.origin.y = 0
    
    modalWindow.makeKeyAndVisible()
    

    As stated, this works great on both iOS 7+ and iOS 8+! When working with subviews, note that the modal's width and height values are switched since it's displaying in portrait. So, if you want to center a subview horizontally, use the modal window's height and the subview's width instead of both views' width.