My app supports portrait and landscape -> Both left and right. I am able to detect if its landscape. But not able to detect left or right. Here is my code
if UIDevice.current.orientation.isLandscape {
// Do some task
}
When user rotates the device i need to detect whether the user rotated to landscape left or landscape right !
Same way inside my above condition I need to check whether its left or right side. How can I detect that?
Thanks
I think you are looking for something like this
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft {
} else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight {
} else {
//not landscape left or right
}
EDIT --------
based on your comments you are looking for interface orientation instead of device orientation.
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)")
}
the code above detects interface orientation...
note how the switch statement still uses UIDeviceOrientation
Below is another method that you may want to use
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("landscape")
} else {
print("portrait")
}
}
Note again that UIDevice Orientation is still used...
Below is a very different but effective approach.
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
}
}
}}
I am doing it like this for now:
public extension UIScreen {
public class var isLandscapeLeft: Bool { UIApplication.shared.statusBarOrientation == .landscapeLeft }
public class var isLandscapeRight: Bool { UIApplication.shared.statusBarOrientation == .landscapeRight }
}
It's as extension to UIScreen just for convenience so its easy to find..
Also to detect when app actually rotates from left to right when I have just landscape enabled, I had to use AppDelegate's function:
func application(_ application: UIApplication, didChangeStatusBarOrientation oldStatusBarOrientation: UIInterfaceOrientation) { ... }
For whatever reason nothing else get's triggered.
Looks like also, you have to use UIApplication.shared.statusBarOrientation when checking from didChangeStatusBarOrientation instead of UIApplication.shared.delegate?.window??.rootViewController?.interfaceOrientation I used for other situations.
I'm setting the orientation for AVCaptureVideoOrientation by getting the current device orientation, however I'm having trouble to get the interface orientation when the device is faceDown or faceUp. Any help would be greatly appreciated. Thanks in advance
private func configureDeviceOrientation() {
var videoOrientation: AVCaptureVideoOrientation {
switch UIDevice.current.orientation {
case .faceUp, .faceDown:
//I don't know whether the interface orientation is landscapeLeft
//or landscapeRight nor do I know how to check.
}
}
interfaceOrientation is deprecated from iOS 8 and this is a framework, therefore I don't have access to UIApplication.shared
I had the same problem with my AVCaptureVideoOrientation.
Just use self.view.window?.windowScene?.interfaceOrientation in place of UIDevice.current.orientation:
switch self.view.window?.windowScene?.interfaceOrientation {
case .portrait:
previewLayer.connection?.videoOrientation = .portrait
case .portraitUpsideDown:
previewLayer.connection?.videoOrientation = .portraitUpsideDown
case .landscapeRight:
previewLayer.connection?.videoOrientation = .landscapeRight
case .landscapeLeft:
previewLayer.connection?.videoOrientation = .landscapeLeft
default:
print("other")
}
This value will be either portrait, portraitUpsideDown, landscapeRight, or landscapeLeft.
Call this code on startup and every time the device changes orientation.
See here for documentation.
Add to viewWillAppear to check if device is rotated:
//Observer for if Device Rotated
NotificationCenter.default.addObserver(self,
selector: #selector(device_rotated),
name:UIDevice.orientationDidChangeNotification,
object: nil)
Add to viewWillDisappear:
NotificationCenter.default.removeObserver(self)
Add to viewController. Function will be called if device is rotated or orientation changed:
#objc func device_rotated(notification:Notification) -> Void{
switch UIDevice.current.orientation {
case .landscapeLeft, .landscapeRight:
print("Landscape")
case .portrait, .portraitUpsideDown:
print("Portrait")
case .faceUp:
print("Face Up")
case .faceDown:
print("Face Down")
default:
print("Default")
}
}
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]
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
}
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.
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
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")
}
}
Swift 4:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if UIDevice.current.orientation.isLandscape {
print("landscape")
} else {
print("portrait")
}
}
To find current device orientation simply use this code:
UIApplication.sharedApplication().statusBarOrientation
for swift 3.0
UIApplication.shared.statusBarOrientation
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)!
}
}
}
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.
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.)
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")
}
}
:)
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
}
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")
}
}
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.
override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
if (toInterfaceOrientation.isLandscape) {
NSLog("Landscape");
}
else {
NSLog("Portrait");
}
}
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)")
}
}
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")
}
Keeping it simple:
let orientation = UIApplication.shared.statusBarOrientation.isLandscape ? "landscape" : "portrait"
I think the best way to do this in modern Objective C and accounting for now deprecated functions is...
UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]);
In swift, that would be.
UIDevice.current.orientation.isLandscape
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.
UIDevice.current.orientation did not work for my compass-type application, because it reports "faceUp" or "faceDown" when the phone is horizontal, regardless of how the screen is oriented. I want to show the direction the user is facing, assuming they're holding the phone in a natural orientation.
UIApplication.shared.statusBarOrientation gave me a deprecated warning "'statusBarOrientation' was deprecated in iOS 13.0: Use the interfaceOrientation property of the window scene instead."
The following did what I needed.
var headingOffset = 0.0
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
switch windowScene?.interfaceOrientation {
case .portrait:
headingOffset = 0.0
print("Reporting orientation as portrait")
case .portraitUpsideDown:
headingOffset = 180.0
print("Reporting orientation as portraitUpsideDown")
case .landscapeLeft:
headingOffset = -90.0
print("Reporting orientation as landscapeLeft")
case .landscapeRight:
headingOffset = 90.0
print("Reporting orientation as landscapeRight")
default:
headingOffset = 0.0
print("Reporting orientation as default")
}
if UIDeviceOrientationIsLandscape(UIDevice.currentDevice().orientation) {
print("landscape")
}
if UIDeviceOrientationIsPortrait(UIDevice.currentDevice().orientation){
print("portrait")
}
How can I check if it's landscape left or right?
you can do something like,
if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft{
}
else if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight{
}
else if UIDevice.currentDevice().orientation == UIDeviceOrientation.UIDeviceOrientationPortraitUpsideDown{
}
else if UIDevice.currentDevice().orientation == UIDeviceOrientation.UIDeviceOrientationPortrait{
}
SWIFT 5
if UIDevice.current.orientation.isLandscape {
} else if UIDevice.current.orientation.isFlat {
} else if UIDevice.current.orientation.isPortrait {
} else if UIDevice.current.orientation.isValidInterfaceOrientation {
}
SWIFT 3
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft {
} else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight {
} else if UIDevice.current.orientation == UIDeviceOrientation.portrait {
} else if UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown {
}
This works on Swift 3 & 4
switch UIApplication.shared.statusBarOrientation {
case .portrait:
//do something
break
case .portraitUpsideDown:
//do something
break
case .landscapeLeft:
//do something
break
case .landscapeRight:
//do something
break
case .unknown:
//default
break
}
Swift 5.0:
UIDevice.current.orientation.isLandscape
UIDevice.current.orientation.isFlat
UIDevice.current.orientation.isPortrait
UIDevice.current.orientation.isValidInterfaceOrientation
isFlat:
Indicating whether the specified orientation is face up or face down (The device is held parallel to the ground with the screen facing downwards or Not).
isValidInterfaceOrientation:
Indicating whether the specified orientation is one of the portrait or landscape orientations.
IMPORTANT NOTE:
If you have set some views to landscape form manually, so "isLandscape" value is not correct.
In this case you can use this condition:
if UIScreen.main.bounds.height < UIScreen.main.bounds.width {
print("LandScape Views")
print("Portrait Views")
}
For example I wanted to play all videos in landscape form while my app was only for portrait form, so in video views I used this condition in order to check if the view is landscape or not, independent of the phone orientation.
UIDeviceOrientation will return a value for that:
enum UIDeviceOrientation : Int {
case Unknown
case Portrait
case PortraitUpsideDown
case LandscapeLeft
case LandscapeRight
case FaceUp
case FaceDown
}
There is one thing that destroy all this answers - it's iOS9 iPad multitasking.
On iOS 9, an iPad app by default opts into iPad multitasking. This means that it must adopt all orientations at all times. Since you have not opted out of iPad multitasking, the runtime assumes that you do adopt all orientations at all times — and thus it doesn't need to bother to ask you what orientations you permit, as it already knows the answer (all of them).
To do right cell size for UICollectionView I do next :
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if UIDevice.current.userInterfaceIdiom == .phone {
return CGSize(width: collectionView.frame.size.width, height: 120)
} else {
var width:CGFloat = 0
let height = 250
// because of iOS9 and iPad multitasking
if (UIApplication.shared.statusBarOrientation.rawValue <= UIInterfaceOrientation.portraitUpsideDown.rawValue) {
width = (collectionView.frame.size.width - 3) / 3
} else {
width = (collectionView.frame.size.width - 4) / 4
}
return CGSize(width: Int(width), height: Int(height))
}
}
and inside viewWillTransition next:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout {
layout.invalidateLayout()
}
}
because it works faster than without.
Swift 3+
switch UIDevice.current.orientation {
case .faceUp:
print("flat - up")
case .faceDown:
print("flat - down")
case .landscapeLeft:
print("landscape - left")
case .landscapeRight:
print("landscape - right")
case .portrait:
print("portrait - normal")
case .portraitUpsideDown:
print("portrait - upsideDown")
case .unknown:
print("unknown")
}
SWIFT 4.2
if UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft {
print("Landscape Left")
}
else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight{
print("Landscape Right")
}
else if UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown{
print("Portrait Upside Down")
}
else if UIDevice.current.orientation == UIDeviceOrientation.portrait {
print("Portrait")
}
I have the following method inside my only ViewController.
override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
println("willAnimateRotationToInterfaceOrientation")
super.willAnimateRotationToInterfaceOrientation(toInterfaceOrientation, duration: duration)
switch (toInterfaceOrientation) {
case .Portrait: println(".Portrait")
case .PortraitUpsideDown: println(".PortraitUpsideDown")
case .LandscapeRight: println(".LandscapeRight")
case .LandscapeLeft: println(".LandscapeLeft")
case .Unknown: println(".Unknown")
}
}
And I enabled all possible orientations in the project settings
But even if I rotate 360 in the simulator (same goes for my iPhone), I never get ".PortraitUpsideDown" printed in the console. Why? It almost seems, like Apple doesn't allow this rotation.
You need to specifically return portrait upside down in supportedInterfaceOrientations() in your base UIViewController
The method implementation should look like so.
override func supportedInterfaceOrientations() -> Int {
return Int(UIInterfaceOrientationMask.All.rawValue)
}