如何确定iOS设备的方向*实际*是否会发生变化?

时间:2013-11-22 15:28:43

标签: ios iphone orientation screen-orientation uiinterfaceorientation

我正在编写此代码,以便对我的应用程序的布局方式进行一些更改,具体取决于它是处于横向还是纵向模式。我已经设置了应用程序以获取有关方向更改的通知,如下所示:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedRotate:) name:UIDeviceOrientationDidChangeNotification object:NULL];

然后定义receivedRotate:

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

    // ... do something
}

但是,只要稍微移动设备,就会调用UIDeviceOrientationDidChangeNotification。例如,UIDeviceOrientation可以是以下任何一种:

UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown

这很棒,但我只是想知道设备方向是纵向还是横向,而且我也只想在方向实际改变时运行此代码 - 从纵向到横向,反之亦然。如果他们一直转动手机,它仍处于横向模式 - 只是一种不同形式的横向模式。什么是确保我的旋转代码仅在必要时运行的理想方法?

4 个答案:

答案 0 :(得分:2)

DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?

iOS 11,Swift 4和Xcode 9.X

无论是否使用AutoLayout,都有多种方法可以获得正确的设备方向,并且可以在使用应用时检测旋转变化,以及在应用启动时获取正确的方向或从后台恢复后。

此解决方案在iOS 11和Xcode 9.X中运行良好

<强> 1。 UIScreen.main.bounds.size:

如果您只是想知道该应用是处于横向模式还是纵向模式,那么最佳起点是viewDidLoad在发布时的rootViewControllerviewWillTransition(toSize:)中的rootViewController let size = UIScreen.main.bounds.size if size.width < size.height { print("Portrait: \(size.width) X \(size.height)") } else { print("Landscape: \(size.width) X \(size.height)") } 如果您想在应用处于后台时检测轮换更改,并应以正确的方向恢复用户界面。

application:didFinishLaunchingWithOptions

这也发生在app / viewController生命周期的早期。

<强> 2。通知中心

如果您需要获取实际的设备方向(包括faceDown,faceUp等)。您想按如下方式添加观察者(即使您在AppDelegate的viewDidLoad方法中执行此操作,第一个通知可能会在device = UIDevice.current device?.beginGeneratingDeviceOrientationNotifications() notificationCenter = Notifi`enter code here`cationCenter.default notificationCenter?.addObserver(self, selector: #selector(deviceOrientationChanged), name: Notification.Name("UIDeviceOrientationDidChangeNotification"), object: nil) 执行后触发

inspectDeviceOrientation()

按如下方式添加选择器。我将其拆分为两部分,以便能够在viewWillTransition(toSize:)

中运行@objc func deviceOrientationChanged() { print("Orientation changed") inspectDeviceOrientation() } func inspectDeviceOrientation() { let orientation = UIDevice.current.orientation switch UIDevice.current.orientation { case .portrait: print("portrait") case .landscapeLeft: print("landscapeLeft") case .landscapeRight: print("landscapeRight") case .portraitUpsideDown: print("portraitUpsideDown") case .faceUp: print("faceUp") case .faceDown: print("faceDown") default: // .unknown print("unknown") } if orientation.isPortrait { print("isPortrait") } if orientation.isLandscape { print("isLandscape") } if orientation.isFlat { print("isFlat") } }
UIDeviceOrientationDidChangeNotification

请注意,.unknown.可能会在发布期间多次发布,在某些情况下可能会viewDidLoad我看到的是在{{1}之后收到第一个正确的方向通知}和viewWillAppear方法,就在viewDidAppear之前,甚至是applicationDidBecomeActive

方向对象将为您提供所有7种可能的方案(来自枚举UIDeviceOrientation定义):

public enum UIDeviceOrientation : Int {
    case unknown
    case portrait // Device oriented vertically, home button on the bottom
    case portraitUpsideDown // Device oriented vertically, home button on the top
    case landscapeLeft // Device oriented horizontally, home button on the right
    case landscapeRight // Device oriented horizontally, home button on the left
    case faceUp // Device oriented flat, face up
    case faceDown // Device oriented flat, face down
}

有趣的是,isPortrait只读Bool变量在UIDeviceOrientation的扩展名中定义如下:

extension UIDeviceOrientation {
    public var isLandscape: Bool { get }
    public var isPortrait: Bool { get }
    public var isFlat: Bool { get }
    public var isValidInterfaceOrientation: Bool { get }
}

第3。 StatusBarOrientation

UIApplication.shared.statusBarOrientation.isLandscape

这也适用于确定方向是纵向还是横向,并提供与第1点相同的结果。您可以在viewDidLoad(适用于应用启动)和viewWillTransition(toSize:)中进行评估,如果来自背景。但它不会向您提供有关通知的上/下,左/右,上/下的详细信息(第2点)

答案 1 :(得分:1)

我相信您所寻找的是UIInterfaceOrientation,而不是UIDeviceOrientation。要使用它,只需在视图控制器中实现以下功能。

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
    //
}

此枚举声明为以下

typedef enum : NSInteger {
   UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
   UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
   UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
   UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
} UIInterfaceOrientation;

答案 2 :(得分:0)

将先前的方向保存在属性中,并将其与当前方向进行比较。

答案 3 :(得分:0)

@ 0x7ffffff和@Kunal Balani的答案是正确的道路,但我建议你看看UIViewController's documentation在iOS 6+应用程序上的轮换处理与在iOS 5及更早版本中处理它的方式,因为你没有提到你是否支持iOS 5(在撰写本答案的时候仍然支持iOS 5)。这将有助于解决您可能遇到的任何问题。我建议您专门查看willRotateToInterfaceOrientation:duration: / willAnimateRotationToInterfaceOrientation:duration: / didRotateFromInterfaceOrientation:以及在轮播生命周期内调用它们的时间。

您肯定希望存储其他答案中提到的上一个方向,这样您就不会多次运行代码。

关于更具“不可知”的具体问题,关于横向与纵向的版本,UIKit's function reference包含许多相关宏,特别是UIInterfaceOrientationIsPortrait()UIInterfaceOrientationIsLandscape()