简体   繁体   English

检测 iOS UIDevice 方向

[英]Detecting iOS UIDevice orientation

I need to detect when the device is in portrait orientation so that I can fire off a special animation.我需要检测设备何时处于纵向,以便我可以触发特殊动画。 But I do not want my view to autorotate.但我不希望我的视图自动旋转。

How do I override a view autorotating when the device is rotated to portrait?当设备旋转到纵向时,如何覆盖自动旋转的视图? My app only needs to display it's view in landscape but it seems I need to support portrait also if I want to be able to detect a rotation to portrait.我的应用程序只需要以横向方式显示它的视图,但如果我希望能够检测到纵向的旋转,我似乎也需要支持纵向。

Try doing the following when the application loads or when your view loads:尝试在应用程序加载或视图加载时执行以下操作:

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

Then add the following method:然后添加以下方法:

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

The above will allow you to register for orientation changes of the device without enabling the autorotate of your view.以上将允许您注册设备的方向更改,而无需启用视图的自动旋转。


Note笔记

In all cases in iOS, when you add an observor, also remove it at appropriate times (possibly, but not always, when the view appears/disappears).在 iOS 中的所有情况下,当您添加观察者时,也要在适当的时间将其删除(可能,但不总是,当视图出现/消失时)。 You can only have "pairs" of observe/unobserve code.您只能拥有“成对”的观察/不观察代码。 If you do not do this the app will crash.如果您不这样做,应用程序将崩溃。 Choosing where to observe/unobserve is beyond the scope of this QA.选择观察/不观察的位置超出了本质量保证的范围。 However you must have an "unobserve" to match the "observe" code above.但是,您必须有一个“unobserve”来匹配上面的“observe”代码。

If you came to this question looking for how to detect an orientation change (without necessarily wanting to disable the rotation), you should also be aware of viewWillTransitionToSize , which is available from iOS 8.如果您遇到这个问题是为了寻找如何检测方向变化(不一定要禁用旋转),您还应该了解 iOS 8 提供的viewWillTransitionToSize

Swift example from 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)
}

And if you don't need to worry about the actual orientation:如果您不需要担心实际方向:

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

    // do something

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
}

Objective-C example from 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];
}

And if you don't need to worry about the actual orientation (taken from this answer ):如果您不需要担心实际方向(取自此答案):

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

See also也可以看看

1) Swift version of David's answer 2) In case you still want to detect orientation when there's no orientation change (Swift vesion of Moe's answer to How Do I detect the orientation of the device on iOS? ) 1) David 答案的 Swift 版本 2) 如果您仍然想在没有方向变化的情况下检测方向(Moe 对如何在 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 function方向改变函数

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

If you do not want to create device object, you can also use如果不想创建设备对象,也可以使用

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

If I understand you correctly, your app is landscape only.如果我理解正确,您的应用程序仅适用于横向。 You can simply specify in the apps setup that it is landscape only and therefore do not need to worry about rotation.您可以简单地在应用程序设置中指定它仅为横向,因此无需担心旋转。 The app will start in landscape and stay there regardless of how the iPad is orientated.无论 iPad 的方向如何,该应用程序都将以横向模式启动并停留在那里。

.UIDeviceOrientationDidChange notification is called many times on iphone even when device did not rotate.即使设备没有旋转, .UIDeviceOrientationDidChange通知也会在 iphone 上多次调用。 Do not know the reason, but if you need it only when device really rotated, then do the following.不知道原因,但如果您仅在设备真正旋转时才需要它,请执行以下操作。

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

The method called from observer should look like this:从观察者调用的方法应该是这样的:

func orientationChanged() {

    if traitCollection.isIphone {

        defer {
            self.previousTraitCollectionForIphone = traitCollection
        }

        guard let previousTraitCollectionForIphone = previousTraitCollectionForIphone else {

            updateView()
            return
        }

        if previousTraitCollectionForIphone != traitCollection {
            updateView()
        }

    } else {
        updateView()
    }
}

In Swift 5.0.在 Swift 5.0 中。

DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape? DeviceOrientation vs. ScreenSize vs StatusBar.isLandscape?

If you want to detect changes of orientation in background, and also need to detect face up/down changes, check this link In Swift, how to get the device orientation correctly right after it's launched?如果您想检测背景中的方向变化,并且还需要检测面朝上/朝下的变化,请检查此链接在 Swift 中,如何在启动后立即正确获取设备方向?

It covers how to correctly detect the orientation in Swift using 3 alternate ways to do it: - viewWillTransitionToSize() - Using Observer - Using the status bar它涵盖了如何使用 3 种替代方法在 Swift 中正确检测方向: - viewWillTransitionToSize() - 使用观察者 - 使用状态栏

Here is some additional code to avoid spurious UI resets or transitions:下面是一些额外的代码,以避免虚假的 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;
    }
}

First disable all but the orientation you want (so that it doesnt rotate)首先禁用除您想要的方向之外的所有方向(以便它不会旋转)

Then like David said just get the device current orientation:然后就像大卫说的那样获取设备当前的方向:

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

Alternatively you can just use the accelerometer yourself (since its how it is done anyway) and check where the gravity is at to see what orientation it has.或者,您可以自己使用加速度计(因为它是如何完成的)并检查重力的位置以查看它的方向。 If you take this approach you can play with the values yourself to get different results.如果您采用这种方法,您可以自己处理这些值以获得不同的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM