In Swift, how to get the device orientation correctly right after it's launched?

后端 未结 5 1827
孤独总比滥情好
孤独总比滥情好 2021-01-12 22:45

I use following code to see if the device is in landscape mode or not:

UIDevice.currentDevice().orientation.isLandscape.boolValue

It works

相关标签:
5条回答
  • 2021-01-12 23:11

    I have tested many times about orientation, so I have summed up some experience.

    In all iPhone devices, except iPhone6(s) plus, the only interface orientation is .portrait. If App is launched in landscape mode, there must be a change of orientation. One will receive the UIDeviceOrientationDidChangeNotification. It's an appropriate time to get the orientation.

    Regarding the launching when in landscape with iPhone6, the orientation after the launch will change once:

    The launching when in landscape with iPhone6 plus, after launch the orientation never changed:

    Two different screenshot with the same app,

    So before the app does change orientation, the orientation is still like in the home page.

    In viewDidLoad, the orientation has not changed yet, the log will be the wrong direction.

    0 讨论(0)
  • 2021-01-12 23:15

    I had a problem to detect which orientation was before isFlat so I put this in my view controller

    let orientation = UIDevice.current.orientation
    
    override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        if  orientation.isPortrait {
            return .portrait
        } else if orientation.isFlat{
            if UIScreen.main.bounds.width < UIScreen.main.bounds.height{
                return .portrait
            } else {
                return .landscape
            }
        } else {
            return .landscape
        }
    }
    
    0 讨论(0)
  • 2021-01-12 23:17

    This worked for me:

    if UIScreen.main.bounds.width > UIScreen.main.bounds.height{
        print("Portraitmode!")
    }
    

    It works on all devices based on the display dimensions: https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Displays/Displays.html

    0 讨论(0)
  • 2021-01-12 23:29

    The isValidInterfaceOrientation should be detected before checking the orientation isLandscape. Don't process the flat message with isValidInterfaceOrientation == false (when it has any value of isLandscape).

    I had a hazzel with this until I read the topic more carefully. With consideration of the isValidInterfaceOrientation it works fine.

    @objc func rotated() {
        if (UIDevice.current.orientation.isValidInterfaceOrientation) {
            if (UIDevice.current.orientation.isLandscape) { 
                if(!bLandscape) {
                    bLandscape = true
                    setupTabBar() // Repaint the app
                }
            } else { // Portait 
                if(bLandscape) {
                    bLandscape = false
                    setupTabBar() // Repaint the app 
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-12 23:30

    DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?

    iOS 11, Swift 4 and Xcode 9.X

    Regardless of using AutoLayout or not, there are several ways to get the right device orientation, and they could be used to detect rotation changes while using the app, as well as getting the right orientation at app launch or after resuming from background.

    This solutions work fine in iOS 11 and Xcode 9.X

    1. UIScreen.main.bounds.size: If you only want to know if the app is in landscape or portrait mode, the best point to start is in viewDidLoad in the rootViewController at launch time and in viewWillTransition(toSize:) in the rootViewController if you want to detect rotation changes while the app is in background, and should resume the UI in the right orientation.

    let size = UIScreen.main.bounds.size
    if size.width < size.height {
        print("Portrait: \(size.width) X \(size.height)")
    } else {
        print("Landscape: \(size.width) X \(size.height)")
    }
    

    This also happens early during the app/viewController life cycles.

    2. NotificationCenter

    If you need to get the actual device orientation (including faceDown, faceUp, etc). you want to add an observer as follows (even if you do it in the application:didFinishLaunchingWithOptions method in the AppDelegate, the first notifications will likely be triggered after the viewDidLoad is executed

    device = UIDevice.current
    device?.beginGeneratingDeviceOrientationNotifications()
    notificationCenter = NotificationCenter.default
    notificationCenter?.addObserver(self, selector: #selector(deviceOrientationChanged),
        name: Notification.Name("UIDeviceOrientationDidChangeNotification"),
        object: nil)
    

    And add the selector as follows. I split it in 2 parts to be able to run inspectDeviceOrientation() in viewWillTransition

    @objc func deviceOrientationChanged() {
        print("Orientation changed")
        inspectDeviceOrientation()
    }
    
    func inspectDeviceOrientation() {
        let orientation = UIDevice.current.orientation
        switch UIDevice.current.orientation {
        case .portrait:
            print("portrait")
        case .landscapeLeft:
            print("landscapeLeft")
        case .landscapeRight:
            print("landscapeRight")
        case .portraitUpsideDown:
            print("portraitUpsideDown")
        case .faceUp:
            print("faceUp")
        case .faceDown:
            print("faceDown")
        default: // .unknown
            print("unknown")
        }
        if orientation.isPortrait { print("isPortrait") }
        if orientation.isLandscape { print("isLandscape") }
        if orientation.isFlat { print("isFlat") }
    }
    

    Note that the UIDeviceOrientationDidChangeNotification may be posted several times during launch, and in some cases it may be .unknown. What I have seen is that the first correct orientation notification is received after the viewDidLoad and viewWillAppear methods, and right before viewDidAppear, or even applicationDidBecomeActive

    The orientation object will give you all 7 possible scenarios(from the enum UIDeviceOrientation definition):

    public enum UIDeviceOrientation : Int {
        case unknown
        case portrait // Device oriented vertically, home button on the bottom
        case portraitUpsideDown // Device oriented vertically, home button on the top
        case landscapeLeft // Device oriented horizontally, home button on the right
        case landscapeRight // Device oriented horizontally, home button on the left
        case faceUp // Device oriented flat, face up
        case faceDown // Device oriented flat, face down
    }
    

    Interestingly, the isPortrait read-only Bool variable is defined in an extension to UIDeviceOrientation as follows:

    extension UIDeviceOrientation {
        public var isLandscape: Bool { get }
        public var isPortrait: Bool { get }
        public var isFlat: Bool { get }
        public var isValidInterfaceOrientation: Bool { get }
    }
    

    3. StatusBarOrientation

    UIApplication.shared.statusBarOrientation.isLandscape 
    

    This also works fine to determine if orientation is portrait or landscape orientation and gives the same results as point 1. You can evaluate it in viewDidLoad (for App launch) and in viewWillTransition(toSize:) if coming from Background. But it won't give you the details of top/bottom, left/right, up/down you get with the notifications (Point 2)

    0 讨论(0)
提交回复
热议问题