检测iOS UIDevice方向


71

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

当设备旋转到纵向时,如何覆盖自动旋转的视图?我的应用程序仅需要以横向显示视图,但是如果我想能够检测到纵向旋转,似乎还需要支持纵向。


注意。仅使用viewDidLayoutSubviews它会处理所有布局更改可能更现代。(回想一下,不久的将来,用户将在设备的Windows中调整应用程序的大小。)现在,响应式布局已成为常态。
Fattie

Answers:


174

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

[[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的所有情况下,添加观察者时,也都应在适当的时间(可能(但并非总是如此)在视图出现/消失时)将其删除。您只能具有“成对”的观察/取消观察代码。如果不这样做,该应用程序将崩溃。选择观察/不观察的位置超出了此质量检查的范围。但是,您必须具有“取消观察”才能与上面的“观察”代码匹配。


在这里必须要注意一些事情。(int)device.orientation在纵向中可以是1或2,在横向中可以是3或4。并且有一个“ 5”,表示设备只是站在桌子上,如果您正在使用UIDeviceOrientationIsLandscape(device.orientation)进行检查,则该设备将作为风景返回。即使您的应用/设备处于纵向模式,也可以得到“横向”答案。
emrahgunduz

1
如果应用启动,直到应用改变方向,UIDevice才会给出方向。iOS> 5的其他可能性[UIApplication sharedApplication] .statusBarOrientation
khunshan 2014年

不要忘了在适当的位置删除观察者(取决于您添加它),否则你将得到异常..
阿姆鲁Lotfy

21

如果您在寻找如何检测方向变化(不必一定要禁用旋转)时遇到了这个问题,那么您还应该知道viewWillTransitionToSize,iOS 8提供了该功能。

来自这里的快速示例

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)
}

这里的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];
}

而且,如果您不必担心实际方向(从此答案中获取):

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    // Do view manipulation here.
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}

也可以看看


即使您最小化应用程序或按下电源按钮,viewWillTransitionToSize也会调用。
Rajneesh071

3

1)David答案的Swift版本2)万一您仍然想在没有方向变化的情况下检测方向(Moe的Swift vesion关于我如何在iOS上检测设备方向的答案)

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

directionChanged功能

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

1

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


让我用一个简单的例子来解释它。我有一个旨在查看风景的应用程序。我的视图显示了一个桌子,上面有一个球。旋转设备以使其纵向时,球将从桌子上滚下来。一切依旧景观,表,背景等
Jace999

1

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

-(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
    }
}

0

首先禁用除所需方向以外的所有方向(以使其不旋转)

然后像David所说的那样,获取设备的当前方向:

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

另外,您也可以自己使用加速度计(因为它无论如何都是如此),并检查重力在哪里以查看其方向。如果您采用这种方法,则可以自己使用值来获得不同的结果。


0

.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()
    }
}

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

0

在Swift 5.0中。

DeviceOrientation vs.ScreenSize vs StatusBar.isLandscape?

如果要检测背景方向的变化,并且还需要检测面朝上/朝下的变化,请检查此链接。在Swift中,如何在启动后立即正确获取设备方向?

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.