如何在iOS设备上检测方向?

72

我想了解如何在iOS上检测设备的方向。我不需要接收更改通知,只需要当前的方向。这似乎是一个相当简单的问题,但我还没有能够理解它。以下是我迄今为止所做的:

UIDevice *myDevice = [UIDevice currentDevice] ;
[myDevice beginGeneratingDeviceOrientationNotifications];
UIDeviceOrientation deviceOrientation = myDevice.orientation;
BOOL isCurrentlyLandscapeView = UIDeviceOrientationIsLandscape(deviceOrientation);
[myDevice endGeneratingDeviceOrientationNotifications];
在我看来这应该可以工作。我启用了设备接收设备方向通知,然后询问它所处的方向,但它没有工作,我不知道原因。
在我的想法里这应该有效。我将设备设置为接收设备方向通知,然后查询它的方向,但结果却不起作用,我不知道原因。

这会有所帮助:http://jayprakashdubey.blogspot.in/2014/07/check-device-orientation.html - Jayprakash Dubey
可能是重复的问题:如何以编程方式确定iPhone界面方向? - Suhaib
13个回答

120

这是一个很老的线程,但并没有真正的解决方案。

我曾经遇到同样的问题,但发现获取UIDeviceOrientation不总是一致的,所以可以尝试使用下面的方法:

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

5
如果可以的话,这是最正确的答案。通过检查这个属性,您可以随时获取界面方向。请注意,无论状态栏是否隐藏,该属性都会被更新,这一点并不重要! - ktolis
3
如果你挑剔,选择不依赖于故障保护,请不要忘记UIInterfaceOrientationPortraitUpsideDown - ArkReversed
这对我很有效,但它根本没有检测到纵向模式。我必须检测它是左侧还是右侧,然后如果都不是,则将其处理为纵向模式。 - Marcel Marino
4
如果应用程序的方向被限制为仅纵向或横向模式,则此方法将无法使用。 - Salman Khakwani
在我的情况下它不起作用,它总是返回纵向。我更改了p-list以接受多个方向。有人知道为什么吗? - ZijunLost
自iOS 9.0+起,statusBarOrientation已被弃用。 - Lal Krishna

76

如果有UIViewController:

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

如果 UIView 存在:

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

UIDevice.h:

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

更新:

将以下代码添加到 xxx-Prefix.pch 中,然后您就可以在任何地方使用它:

// 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

用法:

if (isLandscape) { NSLog(@"Landscape"); }

1
这是一个非常好的答案。我已经仔细查阅了文档 - 它不仅是一个很好的答案,从正确性的角度来看,它也是正确的。值得标记为已核对。 - Dumoko
1
这就是我一直想要的设备方向确定解释。谢谢TONy。 - Morkrom
有趣的是,只有'isLandscape'在我的iPad模拟器上正确触发(其他所有的都返回NO)。我还没有机会在真正的硬件上测试...但是,我喜欢你的方法。谢谢。 - BonanzaDriver
1
UIViewController::interfaceOrientation 返回 UIInterfaceOrientation,而 UIDeviceOrientationIsLandscape 接受 UIDeviceOrientation。这在今天可能有效,但它不具备向前兼容性。 - Pwner
1
'interfaceOrientation'已被弃用:自iOS 8.0起首次被弃用。 - Bill Chan
使用[[UIDevice currentDevice] orientation]代替self.interfaceOrientation - Jason

22

如果你想寻找的内容与屏幕方向有关,那么你首先需要获取方向变化的通知!你可以在viewDidLoad中设置这个东西

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

每当您的设备方向改变时,OrientationDidChange将被调用,您可以根据方向进行自定义操作。


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

    if(Orientation==UIDeviceOrientationLandscapeLeft || Orientation==UIDeviceOrientationLandscapeRight)
    {
    }
    else if(Orientation==UIDeviceOrientationPortrait)
    {
    }
}

1
这对我来说非常完美,因为我只需要在一个ViewController中获取此信息,应用程序的其余部分不应更改其方向。所以谢谢! - CarmenA

22
如果您想直接从加速计获取设备方向,请使用[[UIDevice currentDevice] orientation]。但如果您需要应用程序的当前方向(界面方向),请使用[[UIApplication sharedApplication] statusBarOrientation]

9

UIViewController有一个interfaceOrientation属性,您可以访问该属性以查找视图控制器的当前方向。

至于您的示例,那应该是可以工作的。当您说它不起作用时,您是什么意思?它给您带来了哪些结果,与您期望的结果有何不同?


1
我在iOS模拟器中进行调试,无论设备的方向如何,它总是返回NO。当我在其中设置断点时,我发现deviceOrientation = myDevice.orientation的输出始终为UIDeviceOrientationUnknown,因此它似乎没有正确跟踪方向。 - JusmanX

8

在 Swift 3.0 中

获取设备方向。

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

获取您的应用程序中的设备方向

UIApplication.shared.statusBarOrientation

2
"'statusBarOrientation'在iOS 13.0中已被弃用:请改用窗口场景的interfaceOrientation属性。" - Egel

4

由于当UIViewcontroller方向固定为某个方向时,使用“UIDeviceOrientation”无法得到与设备方向相关的信息,因此最好使用“UIInterfaceOrientation”。

您可以使用“self.interfaceOrientation”从UIViewController中获取方向,但是当您正在将代码进行因式分解时,您可能需要在视图控制器之外(自定义视图、类别等)进行此类测试,因此您仍然可以通过使用“rootviewController”在控制器之外的任何地方访问该信息:

if (UIInterfaceOrientationIsLandscape(view.window.rootViewController.interfaceOrientation)) {
}

2

通过使用CoreMotion的数据,无论是否启用方向锁定,都可以实现这一点。

以下是代码:

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

                            }

}];

1
以下是一些Swift变量,使检测更加容易:
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

1

你解锁了设备方向的硬件锁吗?我的iPad 1边缘有一个。


但是在 iOS 模拟器中它已经无法工作了...我甚至还没有把它放到设备上。 - JusmanX
@JusmanX SO上有一个相关问题:uidevice-currentdevice-orientation-always-null - Martin Lütke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接