Search code examples
iosuikituiwindow

UIWindow orientation inconsistent between iPhone and iPad devices?


I'm trying to create a custom UIWindow for an overlay behavior, and I've seen everywhere that "UIWindow is not orientation based" ; witch is exactly what I want, since I want to match the borders of the physical device.

On the iPhone, everything appends fine, the UIWindow stays consistent, and I have a nice and still behavior ; the borders do not move when I rotate the device: iPhone preview

On the iPad on the over hand, with the same code exactly, I get a rotation animation on my UIWindow layer (that I use to draw the borders), and it makes this strange layout occurring: iPad preview

I don't use the rotation notification ; because I don't want to respond to rotations. I use the UIScreen nativeBounds "non-oriented aware" bounds to make sure I don't have something that is orientation sensitive. This different behaviors across devices makes me inconfortable.

Does someone already run into that kind of strange behaviors? How do you respond to it? Is there a good practice or a workaround?

The complete code of the project, including the sample apps is here: https://github.com/Dean151/RecordingOverlay

The specific code of the overlay and UIWindow subclass are here: https://github.com/Dean151/RecordingOverlay/blob/master/Sources/RecordingOverlay/RecordingOverlay.swift


Solution

  • Turns out that if certains conditions are met, the windows are rotating automatically. I had to override the rotation when all those parameters are met.

    UIWindow will rotate automatically if all of this is true:

    • iOS is at least 9.0
    • device is an iPad
    • Application supports all devices rotations
    • Applications uses a storyboard as it's main interface (declared in info.plist)
    • Applications does not requires fullscreen (declared in info.plist)

    You can detect that using a small snippet:

    @available(iOS 9.0, *)
    var willAutorotate: Bool {
        guard UIDevice.current.userInterfaceIdiom == .pad else {
          return false
        }
    
        let window = UIApplication.shared.delegate?.window ?? nil
        guard UIApplication.shared.supportedInterfaceOrientations(for: window) == .all else {
            return false
        }
    
        let info = Bundle.main.infoDictionary ?? [:]
        guard info["UIRequiresFullScreen"] as? Bool != true else {
            return false
        }
    
        guard info["UILaunchStoryboardName"] != nil else {
            return false
        }
    
        return true
    }
    

    Now that I know when it'll autorotate, I could change the frame and the transform to "cancel" the rotation.