检测 iOS UIDevice 方向

Posted

技术标签:

【中文标题】检测 iOS UIDevice 方向【英文标题】:Detecting iOS UIDevice orientation 【发布时间】:2012-02-03 00:35:33 【问题描述】:

我需要检测设备何时处于纵向,以便触发特殊动画。但我不希望我的视图自动旋转。

当设备旋转为纵向时,如何覆盖自动旋转的视图?我的应用只需要以横向显示它的视图,但如果我希望能够检测到纵向的旋转,我似乎也需要支持纵向。

【问题讨论】:

注意。只使用viewDidLayoutSubviews 可能更现代,它将处理所有布局更改。 (回想一下,在不久的将来,用户将在设备上的窗口中调整应用程序的大小。)反应式布局现在是常态。 【参考方案1】:

在应用程序加载或视图加载时尝试执行以下操作:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
   addObserver:self selector:@selector(orientationChanged:)
   name:UIDeviceOrientationDidChangeNotification
   object:[UIDevice currentDevice]];

然后添加以下方法:

- (void) orientationChanged:(NSNotification *)note

   UIDevice * device = note.object;
   switch(device.orientation)
   
       case UIDeviceOrientationPortrait:
       /* start special animation */
       break;

       case UIDeviceOrientationPortraitUpsideDown:
       /* start special animation */
       break;

       default:
       break;
   ;

以上将允许您注册设备的方向更改,而无需启用视图的自动旋转。


注意

ios 的所有情况下,当您添加观察者时,也要在适当的时候将其删除(可能,但不总是,当视图出现/消失时)。您只能拥有“对”观察/不观察代码。如果您不这样做,应用程序将崩溃。选择观察/不观察的位置超出了本 QA 的范围。但是你必须有一个“unobserve”来匹配上面的“observe”代码。

【讨论】:

这里有些事情你必须小心。 (int)device.orientation 在纵向可以是 1 或 2,在横向可以是 3 或 4。并且有一个“5”表示设备只是站在桌子上,如果您使用 UIDeviceOrientationIsLandscape(device.orientation) 进行检查,则返回为横向。即使您的应用/设备处于纵向模式,您也可以获得此“横向”答案。 UIDevice 在应用启动时不会给出方向,直到应用改变方向。 iOS>5 [UIApplication sharedApplication].statusBarOrientation 的其他可能性 不要忘记在适当的地方移除观察者(取决于你添加它的位置)否则你会得到异常..【参考方案2】:

如果您来这个问题是为了寻找如何检测方向变化(不一定要禁用旋转),您还应该注意 viewWillTransitionToSize,它可从 iOS 8 获得。

来自here 的 Swift 示例

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) 

    coordinator.animateAlongsideTransition( (UIViewControllerTransitionCoordinatorContext) -> Void in

        let orient = UIApplication.sharedApplication().statusBarOrientation

        switch orient 
        case .Portrait:
            println("Portrait")
            // Do something
        default:
            println("Anything But Portrait")
            // Do something else
        

        , completion:  (UIViewControllerTransitionCoordinatorContext) -> Void in
            println("rotation completed")
    )

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

如果您不需要担心实际方向:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) 

    // do something

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)

来自here 的 Objective-C 示例

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
   
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
    
        UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
        // do whatever
     completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
     

    ];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

如果您不需要担心实际方向(取自this answer):

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator

    // Do view manipulation here.
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

另见

iOS 8 Orientation Change Detection iOS8 Day-by-Day :: Day 14 :: Rotation Deprecation

【讨论】:

viewWillTransitionToSize 即使您最小化应用程序或按下电源按钮也会调用。【参考方案3】:

1) 大卫回答的 Swift 版本 2) 如果您仍然想在没有方向变化的情况下检测方向(Moe 对How Do I detect the orientation of the device on iOS? 的回答的Swift 版本)

    // Initial device orientation
    let orientation: UIInterfaceOrientation = UIApplication.sharedApplication().statusBarOrientation
    if(orientation == UIInterfaceOrientation.Unknown)
        // code for Unknown
    
    else if(orientation == UIInterfaceOrientation.Portrait)
        // code for Portrait
    
    else if(orientation == UIInterfaceOrientation.PortraitUpsideDown)
        // code for Portrait
    
    else if(orientation == UIInterfaceOrientation.LandscapeRight)
        // code for Landscape        
    
    else if(orientation == UIInterfaceOrientation.LandscapeLeft)
        // ode for Landscape
    

    // To detect device orientation change
    UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
    NSNotificationCenter.defaultCenter().addObserver(
        self,
        selector: "orientationChanged:",
        name: UIDeviceOrientationDidChangeNotification,
        object: UIDevice.currentDevice())

orientationChanged 函数

func orientationChanged(note: NSNotification)

    let device: UIDevice = note.object as! UIDevice
    switch(device.orientation)
    
        case UIDeviceOrientation.Portrait:
        // code for Portrait
        break
        case UIDeviceOrientation.PortraitUpsideDown:
        // code for Portrait
        break
        case UIDeviceOrientation.LandscapeLeft:
        // code for Landscape
        break
        case UIDeviceOrientation.LandscapeRight:
        // code for Landscape
        break
        case UIDeviceOrientation.Unknown:
        // code for Unknown
        break
        default:
        break
    

【讨论】:

【参考方案4】:

如果我对您的理解正确,您的应用仅是横向应用。您可以简单地在应用程序设置中指定它仅是横向的,因此无需担心旋转。无论 iPad 的方向如何,该应用程序都会以横向方式启动并停留在那里。

【讨论】:

让我用一个简单的例子来解释一下。我有一个旨在横向查看的应用程序。我的视图显示了一张顶部有球的桌子。当设备旋转到纵向时,球滚下桌子。一切都保持风景、桌子、背景等。【参考方案5】:

如果不想创建设备对象,也可以使用

-(void) seObserverForOrientationChanging

    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter]
     addObserver:self selector:@selector(orientationChanged:)
     name:UIDeviceOrientationDidChangeNotification
     object:[UIDevice currentDevice]];



- (void) orientationChanged:(NSNotification *)note

    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
        //Do something in landscape
    
    else 
        //Do something in portrait
    

【讨论】:

【参考方案6】:

首先禁用除您想要的方向之外的所有方向(使其不会旋转)

然后就像大卫说的那样,只需获取设备当前方向:

https://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/MotionEvents/MotionEvents.html

或者,您也可以自己使用加速度计(因为它是如何完成的) 并检查重力在哪里,看看它有什么方向。如果您采用这种方法,您可以自己使用这些值来获得不同的结果。

【讨论】:

【参考方案7】:

.UIDeviceOrientationDidChange 通知在 iPhone 上被多次调用,即使设备没有旋转。不知道是什么原因,如果只有在设备真正旋转时才需要它,那么请执行以下操作。

NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), name: .UIDeviceOrientationDidChange, object: nil)

观察者调用的方法应该是这样的:

func orientationChanged() 

    if traitCollection.isIphone 

        defer 
            self.previousTraitCollectionForIphone = traitCollection
        

        guard let previousTraitCollectionForIphone = previousTraitCollectionForIphone else 

            updateView()
            return
        

        if previousTraitCollectionForIphone != traitCollection 
            updateView()
        

     else 
        updateView()
    

【讨论】:

不错的解决方案。一件事:在 Xcode 8.3 - Swift 3.1 中无法识别 traitCollection.isIphone。使用 traitCollection.userInterfaceIdiom == .phone【参考方案8】:

在 Swift 5.0 中。

DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?

如果您想检测背景中方向的变化,并且还需要检测面部向上/向下变化,请查看此链接In Swift, how to get the device orientation correctly right after it's launched?

它介绍了如何使用 3 种替代方法正确检测 Swift 中的方向: - viewWillTransitionToSize() - 使用观察者 - 使用状态栏

【讨论】:

【参考方案9】:

这里有一些额外的代码可以避免虚假的 UI 重置或转换:

- (void) orientationChanged:(NSNotification *)note

    UIDeviceOrientation newOrientation = ((UIDevice*)note.object).orientation;
    
    // don't do anything if device is flat...
    if (UIDeviceOrientationIsFlat(newOrientation) || newOrientation == UIDeviceOrientationUnknown)
        return;
           
    // ... and only if orientation has changed
    if (newOrientation != self->lastOrientation) 
        // do whatever you need to do to change UI
        
        self->lastOrientation = newOrientation;
    

【讨论】:

以上是关于检测 iOS UIDevice 方向的主要内容,如果未能解决你的问题,请参考以下文章

当设备以横向启动时,UIDevice 方向返回纵向

UIDevice

IOS UIDevice距离传感器(打开 关闭)

IOS工具类获得设备唯一标识(兼容IOS5,6,7)

UIDevice 方向

如何检测我是否有iPhone 2G,3G,3GS