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

问题描述 投票:0回答:4

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

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

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

ios iphone orientation screen-orientation uiinterfaceorientation
4个回答
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)")
}

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

2. NotificationCenter

如果您需要获取实际的设备方向(包括faceDown,faceUp等)。你想要添加一个观察者如下(即使你在AppDelegate的application:didFinishLaunchingWithOptions方法中这样做,第一个通知可能会在执行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.我所看到的是在viewDidLoadviewWillAppear方法之后,在viewDidAppear之前,甚至applicationDidBecomeActive之前收到第一个正确的方向通知

方向对象将为您提供所有7种可能的方案(来自enum 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(用于App启动)和viewWillTransition(toSize:)(如果来自背景)中对其进行评估。但它不会为您提供通知的上/下,左/右,上/下的详细信息(第2点)


1
投票

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

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

此枚举声明如下

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

0
投票

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


0
投票

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

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

至于你对于什么版本的景观与肖像更加“不可知”的具体问题,UIKit's function reference包含许多相关的宏,特别是UIInterfaceOrientationIsPortrait()UIInterfaceOrientationIsLandscape()

© www.soinside.com 2019 - 2024. All rights reserved.