Getting device orientation in Swift

IosSwiftOrientation

Ios Problem Overview


I was wondering how I can get the current device orientation in Swift? I know there are examples for Objective-C, however I haven't been able to get it working in Swift.

I am trying to get the device orientation and put that into an if statement.

This is the line that I am having the most issues with:

[[UIApplication sharedApplication] statusBarOrientation]

Ios Solutions


Solution 1 - Ios

you can use:

override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.currentDevice().orientation{
    case .Portrait:
        text="Portrait"
    case .PortraitUpsideDown:
        text="PortraitUpsideDown"
    case .LandscapeLeft:
        text="LandscapeLeft"
    case .LandscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

SWIFT 3 UPDATE

override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
    var text=""
    switch UIDevice.current.orientation{
    case .portrait:
        text="Portrait"
    case .portraitUpsideDown:
        text="PortraitUpsideDown"
    case .landscapeLeft:
        text="LandscapeLeft"
    case .landscapeRight:
        text="LandscapeRight"
    default:
        text="Another"
    }
    NSLog("You have moved: \(text)")        
}

or

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
}

with Notification you can check: IOS8 Swift: How to detect orientation change?

> NOTE : didRotateFromInterfaceOrientation is Deprecated Use > viewWillTransitionToSize for iOS 2.0 and later

In case of Face up and Face Down this will not work. So we need to use the following.

if UIApplication.shared.statusBarOrientation.isLandscape {
     // activate landscape changes
} else {
     // activate portrait changes
}

Solution 2 - Ios

To get the status bar (and therefor UI) orientation like the Objective-C code you have, it's simply:

UIApplication.sharedApplication().statusBarOrientation

You can also use the orientation property of UIDevice:

UIDevice.currentDevice().orientation

However, that may not match what orientation your UI is in. From the docs:

> The value of the property is a constant that indicates the current > orientation of the device. This value represents the physical > orientation of the device and may be different from the current > orientation of your application’s user interface. See > “UIDeviceOrientation” for descriptions of the possible values.

Solution 3 - Ios

struct DeviceInfo {
struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : UIApplication.shared.statusBarOrientation.isLandscape
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : UIApplication.shared.statusBarOrientation.isPortrait
        }
    }
}}

swift4 answer: this is how I do it,

1.works for all kinds of view controller

2.also work when the user rotates the app

3.also for the first time install the app

Solution 4 - Ios

Apple recently got rid of the idea of Landscape vs. Portrait and prefers we use screen size. However, this works:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if UIDevice.currentDevice().orientation.isLandscape.boolValue {
        print("landscape")
    } else {
        print("portrait")
    }
}

Solution 5 - Ios

Swift 4:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        if UIDevice.current.orientation.isLandscape {
            print("landscape")
        } else {
            print("portrait")
        }
    }

Solution 6 - Ios

To find current device orientation simply use this code:

> UIApplication.sharedApplication().statusBarOrientation

for swift 3.0

> UIApplication.shared.statusBarOrientation

Solution 7 - Ios

> statusBarOrientation is deprecated, so no longer available to use like > in above answers > > In this code can get orientation without worrying about depreciation. Swift 5 > > ioS 13.2 Tested 100%

Your application should allow working in both portrait and landscape to use the below code, otherwise, results will be different

windows.first is main window windows.last is your current window

struct Orientation {
    // indicate current device is in the LandScape orientation
    static var isLandscape: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isLandscape
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape)!
        }
    }
    // indicate current device is in the Portrait orientation
    static var isPortrait: Bool {
        get {
            return UIDevice.current.orientation.isValidInterfaceOrientation
                ? UIDevice.current.orientation.isPortrait
                : (UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isPortrait)!
        }
    }
}

Solution 8 - Ios

I had issues with using InterfaceOrientation, it worked OK except it wasn't accessing the orientation on loading. So I tried this and it's a keeper. This works because the bounds.width is always in reference to the current orientation as opposed to nativeBounds.width which is absolute.

    if UIScreen.mainScreen().bounds.height > UIScreen.mainScreen().bounds.width {
        // do your portrait stuff
    } else {    // in landscape
        // do your landscape stuff
    }

I call this from willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) and from viewDidLoad but it flexible.

Thanks to zSprawl for the pointer in that direction. I should point out that this is only good for iOS 8 and later.

Solution 9 - Ios

So, if Apple is deprecating the whole orientation string thing ("portrait","landscape"), then all you care about is the ratio of width to height. (kinda like @bpedit's answer)

When you divide the width by the height, if the result is less than 1, then the mainScreen or container or whatever is in "portrait" "mode". If the result is greater than 1, it's a "landscape" painting. ;)

override func viewWillAppear(animated: Bool) {
    let size: CGSize = UIScreen.mainScreen().bounds.size
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    if size.width / size.height > 1 {
        print("landscape")
    } else {
        print("portrait")
    }
}

(I'm guessing that if you use this approach then you probably don't really care about specifically handling the condition when the ratio is exactly 1, equal width and height.)

Solution 10 - Ios

Swift 3+

Basically:

NotificationCenter.default.addObserver(self, selector: #selector(self.didOrientationChange(_:)), name: .UIDeviceOrientationDidChange, object: nil)

@objc func didOrientationChange(_ notification: Notification) {
    //const_pickerBottom.constant = 394
    print("other")
    switch UIDevice.current.orientation {
        case .landscapeLeft, .landscapeRight:
            print("landscape")
        case .portrait, .portraitUpsideDown:
            print("portrait")
        default:
            print("other")
    }
}

:)

Solution 11 - Ios

Swift 3, based on Rob's answer

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    if (size.width / size.height > 1) {
        print("landscape")
    } else {
        print("portrait")
    }
}

Solution 12 - Ios

I found that the alternative code in Swift for the Obj-C code

if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) 

is

if UIApplication.shared.statusBarOrientation.isLandscape

Note: we are trying to find the status bar orientation is landscape or not. If it is landscape then the if statement is true.

Solution 13 - Ios

Swift 5 – Solution: Check orientation on app start & during device rotation:

// app start
override func viewDidAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    if let orientation = self.view.window?.windowScene?.interfaceOrientation {
        let landscape = orientation == .landscapeLeft || orientation == .landscapeRight
    }
}

// on rotation
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    let landscape = UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight
}

Solution 14 - Ios

   override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    if (toInterfaceOrientation.isLandscape) {
        NSLog("Landscape");
    }
    else {
        NSLog("Portrait");
    }
}

Solution 15 - Ios

Swift 5

Works in SwiftUI and storyboard based app. Also, check rotation and trait handlers:

struct Orientation {
    
    /// true - if landscape orientation, false - else
    static var isLandscape: Bool {
        orientation?.isLandscape ?? window?.windowScene?.interfaceOrientation.isLandscape ?? false
    }
    
    /// true - if portrait orientation, false - else
    static var isPortrait: Bool {
        orientation?.isPortrait ?? (window?.windowScene?.interfaceOrientation.isPortrait ?? false)
    }
    
    /// true - if flat orientation, false - else
    static var isFlat: Bool {
        orientation?.isFlat ?? false
    }
    
    /// valid orientation or nil
    static var orientation: UIDeviceOrientation? {
        UIDevice.current.orientation.isValidInterfaceOrientation ? UIDevice.current.orientation : nil
    }
    
    /// Current window (for both SwiftUI and storyboard based app)
    static var window: UIWindow? {
        guard let scene = UIApplication.shared.connectedScenes.first,
              let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
              let window = windowSceneDelegate.window else {
            return UIApplication.shared.windows.first
        }
        return window
    }
}

class ViewController: UIViewController {
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        layoutAll()
    }

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        print("viewWillTransition")
        layoutAll()
    }
    
    override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
        super.traitCollectionDidChange(previousTraitCollection)
        print("traitCollectionDidChange")
        layoutAll()
    }
    
    /// Layout content depending on the orientation
    private func layoutAll() {
        // Layout as you need
        print("layoutAll: isLandscape=\(Orientation.isLandscape), isPortrait=\(Orientation.isPortrait), traitCollection=\(traitCollection)")
    }
}

Solution 16 - Ios

For anyone seeing this past iOS 13:

The most reliable way to me is deprecated now, though it is (still) working:

print(UIApplication.shared.statusBarOrientation.isPortrait)

What seems to be the way to go now:

if UIApplication.shared.windows.first?.
windowScene?.interfaceOrientation.isPortrait ?? true {
    print("Portrait")
} else {
    print("Landscape")
}

Solution 17 - Ios

Try to use horizontalSizeClass & verticalSizeClass:

import SwiftUI

struct DemoView: View {
    
    @Environment(\.horizontalSizeClass) var hSizeClass
    @Environment(\.verticalSizeClass) var vSizeClass
    
    var body: some View {
        VStack {
            if hSizeClass == .compact && vSizeClass == .regular {
                VStack {
                    Text("Vertical View")
                }
            } else {
                HStack {
                    Text("Horizontal View")
                }
            }
        }
    }
}

Found it in this tutorial. Related Apple's documentation.

Solution 18 - Ios

Keeping it simple:

let orientation = UIApplication.shared.statusBarOrientation.isLandscape ? "landscape" : "portrait"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser3746428View Question on Stackoverflow
Solution 1 - IosMiguelView Answer on Stackoverflow
Solution 2 - IosMike SView Answer on Stackoverflow
Solution 3 - IosErnie SenderView Answer on Stackoverflow
Solution 4 - IoszSprawlView Answer on Stackoverflow
Solution 5 - IosFBCView Answer on Stackoverflow
Solution 6 - IosUsman NisarView Answer on Stackoverflow
Solution 7 - IosMalith KuruwitaView Answer on Stackoverflow
Solution 8 - IosbpeditView Answer on Stackoverflow
Solution 9 - IosRobView Answer on Stackoverflow
Solution 10 - IosstakovereserView Answer on Stackoverflow
Solution 11 - IosJohan TingbackeView Answer on Stackoverflow
Solution 12 - IosAkarsh SEGGEMUView Answer on Stackoverflow
Solution 13 - IosMarian KönigView Answer on Stackoverflow
Solution 14 - IosSanjuView Answer on Stackoverflow
Solution 15 - IosAlexander VolkovView Answer on Stackoverflow
Solution 16 - IosJochen BirkleView Answer on Stackoverflow
Solution 17 - Iosivamax9View Answer on Stackoverflow
Solution 18 - IosJohn DohertyView Answer on Stackoverflow