Detect the landscape orientation left or right - ios

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.

Related

How to know the current orientation of a iDevice

I'm doing an app for Mathematics lessons & exercices...
I have only coded the MainMenu, but I've got a problem.
Indeed, I would like to know the current orientation to set up my stuff.
However, I tried different ways to know the current orientation, but I didn't succeed :
if UIDevice.current.orientation == UIDeviceOrientation.portrait {
NSLog("Portrait")
}
else if UIDevice.current.orientation == UIDeviceOrientation.landscapeRight || UIDevice.current.orientation == UIDeviceOrientation.landscapeRight {
NSLog ("Landscape")
}
I also see this answer, but it's not working (or maybe I haven't understood well) : Getting device orientation in Swift , bu
I would like to specify that I'm in UIViewController in the ViewDidLoad().
Thanks for your help 👨‍💻
I set up a little prototype app with a button which checks for device orientation changes when pressed. Here is a link to the documentation which hopefully helps further your project along.
class ViewController: UIViewController {
let device = UIDevice.current
override func viewDidLoad() {
super.viewDidLoad()
device.beginGeneratingDeviceOrientationNotifications()
}
#IBAction func orientation(_ sender: UIButton) {
if device.isGeneratingDeviceOrientationNotifications {
switch device.orientation {
case .landscapeLeft:
print("Landscape Left")
case .portrait:
print("Portrait")
case .landscapeRight:
print("Right")
case .portraitUpsideDown:
print("Upside down")
case .unknown:
print("Unknown")
default:
print("Else")
}
}
}
}

How to check if device in landscape or portrait mode in flat position

There are some questions about device orientation and some users answered like this:
if UIDevice.current.orientation.isLandscape {
print("landscape")
} else {
print("portrait")
}
Which is totally wrong because they don't know that it can have the third result: isFlat
So it can return three different results:
if UIDevice.current.orientation.isLandscape {
print("landscape")
} else if UIDevice.current.orientation.isFlat {
print("flat")
} else { // UIDevice.current.orientation.isPortrait
print("portrait")
}
So if a device is in flat position (isFlat) how to check if that device shows content in landscape or portrait mode?
Update
Only one of them can be true
If isFlat returns true then both isLandscape and isPortrait return false
Update 2
I ended up using:
private func isLandscape() -> Bool {
return self.view.frame.width > self.view.frame.height
}
Or we can use UIApplication.shared.statusBarOrientation.isLandscape

Detecting orientation on loading

When my simulator is in portrait and when my viewcontroller loads initially, it prints out Landscape instead of Portrait but when I change the orientaiton, it correctly displays the orientation so forth. I did the following
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if (UIDevice.current.orientation == UIDeviceOrientation.portrait || UIDevice.current.orientation == UIDeviceOrientation.portraitUpsideDown)
{
print("Portrait")
}
else
{
print("Landscape")
}
}
I have no idea why it is displaying wrong orientation when it loads initially but once I rotate everything seems to work.
P.S. It seems like when simulator initially loads, the orientaiton is unknown, so it is choosing the else condition, how to avoid this from happening and identify the correct orientaiton?
You can check current orientation by UIApplication.shared.statusBarOrientation.isPortrait or UIApplication.shared.statusBarOrientation.isLandscape.
if UIDevice.currentDevice().orientation.isLandscape.boolValue {
print("landscape")
} else {
print("portrait")
}

Read orientation of device even though portrait is only enabled [duplicate]

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")
}

iOS viewWillTransitionToSize and device orientation

I'm using viewWillTransitionToSize to detect when a device is rotating to landscape. Depending on the target size, I can detect if heading for landscape and adjust my traits as required...
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
if size.width > size.height {
self.setOverrideTraitCollection(UITraitCollection(horizontalSizeClass: UIUserInterfaceSizeClass.Regular), forChildViewController: viewController)
}
else{
self.setOverrideTraitCollection(nil, forChildViewController: viewController)
}
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}
However, I want to be able to detect whether my device is transitioning to landscape-left or landscape-right. This will allow me to create different behaviours or views, depending on specific orientation of device. (left or right).
Is this possible without using any deprecated functions?
I thought of using status-bar orientation...
let orientation = UIApplication.sharedApplication().statusBarOrientation;
if( orientation == UIInterfaceOrientation.LandscapeLeft )
{
// Do something
}
else if( orientation == UIInterfaceOrientation.LandscapeRight )
{
// Do something else
}
...but that doesn't help because this appears to give the 'old' status orientation.
How can I get the specific target orientation?
You can get orientation while rotating use UIViewControllerTransitionCoordinator as follows:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
// will execute before rotation
coordinator.animate(alongsideTransition: { (context: UIViewControllerTransitionCoordinatorContext) in
// will execute during rotation
let orientation = UIApplication.shared.statusBarOrientation
if orientation == .landscapeLeft
{
// Do something
}
else if orientation == .landscapeRight
{
// Do something else
}
}) { (context: UIViewControllerTransitionCoordinatorContext) in
// will execute after rotation
}
}
Use [UIDevice currentDevice].orientation

Resources