iOS设备方向忽略方向锁定

Mar*_*bst 30 iphone objective-c orientation ios

我想查询iPhone当前的方向.使用

[UIDevice currentDevice].orientation
Run Code Online (Sandbox Code Playgroud)

只要设备没有方向锁定,就可以正常工作.但是,如果它被锁定,它始终以锁定方向响应,而不是以设备的实际方向响应.

是否有高级方法来获取实际的设备方向?

Sat*_*ito 32

您也可以使用CoreMotion

方向检测算法:

  • 如果abs(y)<abs(x)您的iPhone处于横向位置,请查看x的符号以检测右侧或左侧

  • 否则你的iPhone处于纵向位置,看起来是y的标志来检测或倒置.

  • 如果您对面朝上或朝下感兴趣,请查看z的值.


import CoreMotion
Run Code Online (Sandbox Code Playgroud)
var uMM: CMMotionManager!

override func
viewWillAppear( p: Bool ) {
    super.viewWillAppear( p )
    uMM = CMMotionManager()
    uMM.accelerometerUpdateInterval = 0.2

    //  Using main queue is not recommended. So create new operation queue and pass it to startAccelerometerUpdatesToQueue.
    //  Dispatch U/I code to main thread using dispach_async in the handler.
    uMM.startAccelerometerUpdatesToQueue( NSOperationQueue() ) { p, _ in
        if p != nil {
            println(
                abs( p.acceleration.y ) < abs( p.acceleration.x )
                ?   p.acceleration.x > 0 ? "Right"  :   "Left"
                :   p.acceleration.y > 0 ? "Down"   :   "Up"
            )
        }
    }
}

override func
viewDidDisappear( p: Bool ) {
    super.viewDidDisappear( p )
    uMM.stopAccelerometerUpdates()
}
Run Code Online (Sandbox Code Playgroud)


Eva*_*ski 9

该功能是正确的.如果它始终返回设备方向,即使它被锁定,也会触发方向更改通知.这会破坏锁定的目的.

要回答您的问题,在没有使用私有API的情况下,无法从加速度计读取原始值.

编辑:

在查看文档后,UIAccelerometer类似乎提供了这些数据,即使方向被锁定也是如此.此更改已应用于iOS 4及更高版本.即使您可以使用此数据,仍需要对其进行处理以确定方向.这不是一项容易的任务,因为您需要不断监视更改并将它们与旧值进行比较.

另外,请查看本指南以处理运动事件.这可能为您提供另一种确定方向的途径.

  • 我不同意你的第一句话。设备方向通知是通知设备的方向而不是接口。从理论上讲,无论旋转锁定如何,都应通知它。 (2认同)

Jon*_*nny 8

设置您的视图控制器或其他任何支持UIAccelerometerProtocol,并开始侦听更改(您可以将其设置为10赫兹).

#define kAccelerometerFrequency        10.0 //Hz
-(void)viewDidAppear:(BOOL)animated {
    DLog(@"viewDidAppear");
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
    a.updateInterval = 1 / kAccelerometerFrequency;
    a.delegate = self;
}

-(void)viewWillDisappear:(BOOL)animated {
    DLog(@"viewWillDisappear");
    UIAccelerometer* a = [UIAccelerometer sharedAccelerometer];
    a.delegate = nil;
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
}

#ifdef DEBUG
+(NSString*)orientationToText:(const UIInterfaceOrientation)ORIENTATION {
    switch (ORIENTATION) {
        case UIInterfaceOrientationPortrait:
            return @"UIInterfaceOrientationPortrait";
        case UIInterfaceOrientationPortraitUpsideDown:
            return @"UIInterfaceOrientationPortraitUpsideDown";
        case UIInterfaceOrientationLandscapeLeft:
            return @"UIInterfaceOrientationLandscapeLeft";
        case UIInterfaceOrientationLandscapeRight:
            return @"UIInterfaceOrientationLandscapeRight";
    }
    return @"Unknown orientation!";
}
#endif

#pragma mark UIAccelerometerDelegate
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
    UIInterfaceOrientation orientationNew;
    if (acceleration.x >= 0.75) {
        orientationNew = UIInterfaceOrientationLandscapeLeft;
    }
    else if (acceleration.x <= -0.75) {
        orientationNew = UIInterfaceOrientationLandscapeRight;
    }
    else if (acceleration.y <= -0.75) {
        orientationNew = UIInterfaceOrientationPortrait;
    }
    else if (acceleration.y >= 0.75) {
        orientationNew = UIInterfaceOrientationPortraitUpsideDown;
    }
    else {
        // Consider same as last time
        return;
    }

    if (orientationNew == orientationLast)
        return;

    NSLog(@"Going from %@ to %@!", [[self class] orientationToText:orientationLast], [[self class] orientationToText:orientationNew]);
    orientationLast = orientationNew;
}
#pragma mark -
Run Code Online (Sandbox Code Playgroud)

您需要定义UIInterfaceOrientation orientationLast为成员变量并进行设置.


gra*_*rks 5

当设备方向锁定时,UIAccelerometer类继续运行.你必须找出自己的方法将变量转换为方向值,但它不应该特别复杂.

与Apple的AcceleromoterGraph示例应用程序一起玩,看看加速度计在不同方向输出的值.


bee*_*con 5

处理所有6个方向

虽然我们不经常关心FaceUp/ FaceDown定向,但它们仍然很重要.

将它们考虑在内会对方向变化产生更合适的灵敏度,而将它们排除可能会导致亚稳态和滞后现象.

这是我处理它的方式 -

- (void)startMonitoring
{
    [self.motionManager startAccelerometerUpdatesToQueue:self.opQueue withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {

        if (error != nil)
        {
            NSLog(@"Accelerometer error: %@", error);
        }
        else
        {
            float const threshold = 40.0;

            BOOL (^isNearValue) (float value1, float value2) = ^BOOL(float value1, float value2)
            {
                return fabsf(value1 - value2) < threshold;
            };

            BOOL (^isNearValueABS) (float value1, float value2) = ^BOOL(float value1, float value2)
            {
                return isNearValue(fabsf(value1), fabsf(value2));
            };

            float yxAtan = (atan2(accelerometerData.acceleration.y, accelerometerData.acceleration.x)) * 180 / M_PI;
            float zyAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.y)) * 180 / M_PI;
            float zxAtan = (atan2(accelerometerData.acceleration.z, accelerometerData.acceleration.x)) * 180 / M_PI;

            UIDeviceOrientation orientation = self.orientation;

            if (isNearValue(-90.0, yxAtan) && isNearValueABS(180.0, zyAtan))
            {
                orientation = UIDeviceOrientationPortrait;
            }
            else if (isNearValueABS(180.0, yxAtan) && isNearValueABS(180.0, zxAtan))
            {
                orientation = UIDeviceOrientationLandscapeLeft;
            }
            else if (isNearValueABS(0.0, yxAtan) && isNearValueABS(0.0, zxAtan))
            {
                orientation = UIDeviceOrientationLandscapeRight;
            }
            else if (isNearValue(90.0, yxAtan) && isNearValueABS(0.0, zyAtan))
            {
                orientation = UIDeviceOrientationPortraitUpsideDown;
            }
            else if (isNearValue(-90.0, zyAtan) && isNearValue(-90.0, zxAtan))
            {
                orientation = UIDeviceOrientationFaceUp;
            }
            else if (isNearValue(90.0, zyAtan) && isNearValue(90.0, zxAtan))
            {
                orientation = UIDeviceOrientationFaceDown;
            }

            if (self.orientation != orientation)
            {
                dispatch_async(dispatch_get_main_queue(), ^{

                    [self orientationDidChange:orientation];
                });
            }
        }
    }];
}
Run Code Online (Sandbox Code Playgroud)

另外,我添加了threshold40.0(而不是45.0)的值.这使得变化不那么敏感,从而防止了拐点处的滞后现象.

如果您只想对主要4个方向的变化做出反应,那么就这样做吧

if (UIDeviceOrientationIsPortrait(orientation) || UIDeviceOrientationIsLandscape(orientation))
{
     // Do something
}
Run Code Online (Sandbox Code Playgroud)