How Do I detect the orientation of the device on iOS?
Asked Answered
W

13

72

I have a question on how to detect the device orientation on iOS. I don't need to receive change notifications, just the current orientation itself. This seems to be a rather simple question, but I haven't been able to wrap my head around it. Below is what I have done so far:

UIDevice *myDevice = [UIDevice currentDevice] ;
[myDevice beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation deviceOrientation = myDevice.orientation;
BOOL isCurrentlyLandscapeView = UIDeviceOrientationIsLandscape(deviceOrientation);
[myDevice endGeneratingDeviceOrientationNotifications];

In my mind this should work. I enable the device to receive device orientation notices, then ask for what orientation it is in, but then it is not working and I don't know why.

Walter answered 5/4, 2011 at 23:12 Comment(2)
This will help : jayprakashdubey.blogspot.in/2014/07/…Handfast
Possible duplicate of How to programmatically determine iPhone interface orientation?Kos
L
120

Really old thread, but no real solution.

I Had the same problem, but found out that getting The UIDeviceOrientation isn't always consistent, so instead use this:

UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

if(orientation == 0) //Default orientation 
    //UI is in Default (Portrait) -- this is really a just a failsafe. 
else if(orientation == UIInterfaceOrientationPortrait)
    //Do something if the orientation is in Portrait
else if(orientation == UIInterfaceOrientationLandscapeLeft)
    // Do something if Left
else if(orientation == UIInterfaceOrientationLandscapeRight)
    //Do something if right
Lowgrade answered 25/3, 2012 at 0:22 Comment(6)
This is the most correct answer if I may. This way, you can get the interface orientation at any time by simply checking this property. Note that it does not matter whether the status bar is hidden or not, the property will be updated no matter what!Mulch
If you're picky and choose to not rely on the failsafe, don't forget UIInterfaceOrientationPortraitUpsideDown.Arthur
This works for me, except it wasn't detecting portrait at all. I had to detect if it was right or left and then if it was neither, handle it as portrait.Fulk
This won't work if the Application's Orientation is restricted to either Portrait mode or Landscape Mode only.Pseudonymous
It doesn't work in my case, it always returns portrait. I changed the p-list to accept multiple orientations. Anyone knows why?Photocathode
statusBarOrientation is deprecated since iOS 9.0+Urinary
C
76

if UIViewController:

if (UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
    // 
}

if UIView:

if (UIDeviceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation))
{
    //
}

UIDevice.h:

#define UIDeviceOrientationIsPortrait(orientation)  ((orientation) == UIDeviceOrientationPortrait || (orientation) == UIDeviceOrientationPortraitUpsideDown)
#define UIDeviceOrientationIsLandscape(orientation) ((orientation) == UIDeviceOrientationLandscapeLeft || (orientation) == UIDeviceOrientationLandscapeRight)

Updated:

add this code to xxx-Prefix.pch then you can use it anywhere:

// check device orientation
#define dDeviceOrientation [[UIDevice currentDevice] orientation]
#define isPortrait  UIDeviceOrientationIsPortrait(dDeviceOrientation)
#define isLandscape UIDeviceOrientationIsLandscape(dDeviceOrientation)
#define isFaceUp    dDeviceOrientation == UIDeviceOrientationFaceUp   ? YES : NO
#define isFaceDown  dDeviceOrientation == UIDeviceOrientationFaceDown ? YES : NO

usage:

if (isLandscape) { NSLog(@"Landscape"); }
Cardona answered 12/12, 2012 at 9:49 Comment(6)
This is a very great answer. I've double-checked with documentation - more that it is a great answer, it is a correct one from the point of view of correctitude. Deserves to be marked as Checked.Bimestrial
This is all I ever wanted in a device orientation determination explanation. Thank you TONy. WGene
Interestingly enough only 'isLandscape' seems to fire correctly on my iPad simulator (all the others return NO regardless). Haven't had a chance yet to test on my real hardware ... but, I love your approach. Thx.Coronado
UIViewController::interfaceOrientation returns UIInterfaceOrientation, while UIDeviceOrientationIsLandscape accepts a UIDeviceOrientation. This may work today, but it is not forwards compatible.Contradistinction
'interfaceOrientation' is deprecated: first deprecated in iOS 8.0Picrate
use [[UIDevice currentDevice] orientation] in place of self.interfaceOrientationContinental
S
22

For what You looking for first you have to Get Notification if Orientation Changed! You Can set This Thing in viewDidLoad like

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(OrientationDidChange:) name:UIDeviceOrientationDidChangeNotification object:nil];

and whenever Orientation of your Device changed OrientationDidChange Called where You can do whatever You Want as Per Orientation

-(void)OrientationDidChange:(NSNotification*)notification
{
    UIDeviceOrientation Orientation=[[UIDevice currentDevice]orientation];

    if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight)
    {
    }
    else if(Orientation==UIDeviceOrientationPortrait)
    {
    }
}
Saltzman answered 30/10, 2014 at 12:30 Comment(1)
This actually works perfectly for me because I need this information in only one ViewController, the rest of the app shouldn't change it orientation. So thank you!Nerta
J
22

If you want to get device orientation directly from accelerometer use [[UIDevice currentDevice] orientation]. But if you need current orientation of your application(interface orientation) use [[UIApplication sharedApplication] statusBarOrientation].

Jimjams answered 7/1, 2015 at 22:56 Comment(0)
H
9

UIViewController has an interfaceOrientation property that you can access to find out the current orientation of a view controller.

As for your example, that should work. When you say it isn't working, what do you mean? What results does it give you versus what you expected?

Homunculus answered 5/4, 2011 at 23:15 Comment(1)
I was debugging it in the iOS simulator, and regardless what the orientation of the device it always returns NO. When I put a breakpoint at it, I find out that the output of deviceOrientation = myDevice.orientation is always UIDeviceOrientationUnknown, so it doesn't look like it's tracking the orientation properly.Walter
U
8

In Swift 3.0

to get device orientation.

/* return current device orientation.
   This will return UIDeviceOrientationUnknown unless device orientation notifications are being generated. 
*/
UIDevice.current.orientation

to get device orientation from your app

UIApplication.shared.statusBarOrientation
Ultimately answered 22/12, 2016 at 13:34 Comment(1)
"'statusBarOrientation' was deprecated in iOS 13.0: Use the interfaceOrientation property of the window scene instead." Here is the reference #25797045Malda
S
4

Wasn't satisfied by "UIDeviceOrientation" because when a UIViewcontroller orientation is fixed to a specific orientation you don't get a pertinent information with the device orientation, so the right thing to do is using "UIInterfaceOrientation".

You can get the orientation from the UIViewController with a "self.interfaceOrientation", but when you are factorizing our code, you might need to do this kind of test outside a view controller, (custom view, a category…), so you still can access the information anywhere outside the controller by using the rootviewController:

if (UIInterfaceOrientationIsLandscape(view.window.rootViewController.interfaceOrientation)) {
}
Stonechat answered 12/7, 2013 at 8:6 Comment(0)
C
2

There's a way to achieve this whether the orientation lock is enabled or not by using data from CoreMotion. This is the code:

#import <CoreMotion/CoreMotion.h> 

    CMMotionManager *cm=[[CMMotionManager alloc] init];
    cm.deviceMotionUpdateInterval=0.2f;
    [cm startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue]
                            withHandler:^(CMDeviceMotion *data, NSError *error) {

                            if(fabs(data.gravity.x)>fabs(data.gravity.y)){
                                    NSLog(@"LANSCAPE");
                                if(data.gravity.x>=0){
                                    NSLog(@"LEFT");
                                }
                                else{
                                    NSLog(@"RIGHT");
                                }

                        }
                        else{
                                NSLog(@"PORTRAIT");
                                if(data.gravity.y>=0){
                                    NSLog(@"DOWN");
                                }
                                else{

                                    NSLog(@"UP");
                                }

                            }

}];
Canterbury answered 24/8, 2015 at 3:23 Comment(0)
C
1

Have you unlocked the hardware lock for device orientation? There is one at the edge of my iPad 1.

Clouse answered 5/4, 2011 at 23:24 Comment(2)
but it already doesn't work in the iOS simulator though...I'm not even putting it on the device yet.Walter
@Walter There is a related question at SO: uidevice-currentdevice-orientation-always-nullGeomancy
C
1

Here is some Swift variables to make detection easier:

let LANDSCAPE_RIGHT: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight
let LANDSCAPE_LEFT: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft
let LANDSCAPE: Bool = LANDSCAPE_LEFT || LANDSCAPE_RIGHT
let PORTRAIT_NORMAL: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait
let PORTRAIT_REVERSE: Bool = UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown
let PORTRAIT: Bool = PORTRAIT_REVERSE || PORTRAIT_NORMAL
Compel answered 20/1, 2016 at 0:33 Comment(0)
L
0

My current way of doing this:

+ (BOOL)isPortrait {
    let window = UIApplication.sharedApplication.delegate.window;
    if(window.rootViewController) {
        let orientation =
        window.rootViewController.interfaceOrientation;
        return UIInterfaceOrientationIsPortrait(orientation);
    } else {
        let orientation =
        UIApplication.sharedApplication.statusBarOrientation;
        return UIInterfaceOrientationIsPortrait(orientation);
    }
}

If there is for some reason no rootViewController yet fail safe to statusBarOrientation...

Lili answered 18/7, 2019 at 1:32 Comment(0)
L
0

And the best reliable way in swift :

public extension UIScreen {

    public class var isPortrait: Bool {
        UIApplication.shared.delegate?.window??.rootViewController?.interfaceOrientation.isPortrait ??
                UIApplication.shared.statusBarOrientation.isPortrait
    }

    public class var isLandscape: Bool { !isPortrait }
}
Lili answered 23/12, 2019 at 18:53 Comment(0)
H
0

This is my solution with Combine, which is quite easy to use with SwiftUI or regular Swift Object. A singleton object (static instance) is better than the "environment" for this kind of truly global object.

// Singleton object to keep the interface orientation (and any other global state)
class SceneContext: ObservableObject {
    @Published var interfaceOrientation = UIInterfaceOrientation.portrait
    static let shared = SceneContext()
}

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    ...
    func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
        SceneContext.shared.interfaceOrientation = windowScene.interfaceOrientation
    }
}

    // if you want to execute some code whenever the orientation changes in SwiftUI
    someView {
        ....
    }
    .onReceive(SceneContext.shared.$interfaceOrientation) { (orientation) in
        // do something with the new orientation
    }

    // if you want to execute some code whenever the orientation changes in a regular Swift object
    let pub = SceneContext.shared.$interfaceOrientation.sink(receiveValue: { (orientation) in
            // do something with the new orientation
            ...
        }) 

Hersh answered 24/4, 2021 at 23:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.