iOS device orientation disregarding orientation lock

后端 未结 10 1247
天涯浪人
天涯浪人 2020-11-29 01:59

I want to query the orientation the iPhone is currently in. Using

[UIDevice currentDevice].orientation

works as long as the device isn\'t

相关标签:
10条回答
  • 2020-11-29 02:45

    That functionality is correct. If it always returned the device orientation, even if it was locked, the orientation changed notifications would fire. This would defeat the purpose of the lock.

    To answer your question, there is no way to read the raw values from the accelerometer, without using private APIs.

    Edit:

    After reviewing the documentation, it seems that the UIAccelerometer class provides this data, even when the orientation is locked. This change was applied in iOS 4 and above. Even though you can use this data, you still need to process it to determine the orientation. This is not an easy task as you need to monitor the changes constantly and compare them to older values.

    Also, take a look at this guide for handling motion events. This may provide you with another route to determining the orientation.

    0 讨论(0)
  • 2020-11-29 02:45

    my solution using coremotion,it work even when the device has his orientation locked.

        let motionManager: CMMotionManager = CMMotionManager()
    

    on the did load method

    motionManager.deviceMotionUpdateInterval = 0.01
        if motionManager.accelerometerAvailable{
            let queue = NSOperationQueue()
            motionManager.startAccelerometerUpdatesToQueue(queue, withHandler:
                {data, error in
    
                    guard let data = data else{
                        return
                    }
                    let angle = (atan2(data.acceleration.y,data.acceleration.x))*180/M_PI;
    
                    print(angle)
                    if(fabs(angle)<=45){
                        self.orientation = AVCaptureVideoOrientation.LandscapeLeft
                        print("landscape left")
                    }else if((fabs(angle)>45)&&(fabs(angle)<135)){
    
                        if(angle>0){
                            self.orientation = AVCaptureVideoOrientation.PortraitUpsideDown
                            print("portrait upside Down")
    
    
                        }else{
                            self.orientation = AVCaptureVideoOrientation.Portrait
                            print("portrait")
    
                        }
                    }else{
                        self.orientation = AVCaptureVideoOrientation.LandscapeRight
                        print("landscape right")
    
                    }
    
    
                }
            )
        } else {
            print("Accelerometer is not available")
        }
    

    hope it helps.

    0 讨论(0)
  • 2020-11-29 02:46

    Here is an example of detect device rotation and return UIDeviceOrientation. This solution using CoreMotion and works in all cases.

    Example

    let orientationManager = APOrientationManager()
    orientationManager.delegate = self
    /// start detect rotation
    orientationManager.startMeasuring()
    
    /// get current interface orientation
    let orientation = orientationManager.currentInterfaceOrientation()
    print(orientation.rawValue)
    
    /// stop detect rotation
    orientationManager.stopMeasuring()
    orientationManager.delegate = nil
    

    conform delegate

    extension ViewController: APOrientationManagerDelegate {
        func didChange(deviceOrientation: UIDeviceOrientation) {
            /// update UI in main thread
        }
    }
    

    APOrientationManager.swift

    import Foundation
    import CoreMotion
    import AVFoundation
    import UIKit
    
    protocol APOrientationManagerDelegate: class {
        func didChange(deviceOrientation: UIDeviceOrientation)
    }
    
    class APOrientationManager {
    
        private let motionManager = CMMotionManager()
        private let queue = OperationQueue()
        private var deviceOrientation: UIDeviceOrientation = .unknown
        weak var delegate: APOrientationManagerDelegate?
    
        init() {
            motionManager.accelerometerUpdateInterval = 1.0
            motionManager.deviceMotionUpdateInterval = 1.0
            motionManager.gyroUpdateInterval = 1.0
            motionManager.magnetometerUpdateInterval = 1.0
        }
    
        func startMeasuring() {
            guard motionManager.isDeviceMotionAvailable else {
                return
            }
            motionManager.startAccelerometerUpdates(to: queue) { [weak self] (accelerometerData, error) in
                guard let strongSelf = self else {
                    return
                }
                guard let accelerometerData = accelerometerData else {
                    return
                }
    
                let acceleration = accelerometerData.acceleration
                let xx = -acceleration.x
                let yy = acceleration.y
                let z = acceleration.z
                let angle = atan2(yy, xx)
                var deviceOrientation = strongSelf.deviceOrientation
                let absoluteZ = fabs(z)
    
                if deviceOrientation == .faceUp || deviceOrientation == .faceDown {
                    if absoluteZ < 0.845 {
                        if angle < -2.6 {
                            deviceOrientation = .landscapeRight
                        } else if angle > -2.05 && angle < -1.1 {
                            deviceOrientation = .portrait
                        } else if angle > -0.48 && angle < 0.48 {
                            deviceOrientation = .landscapeLeft
                        } else if angle > 1.08 && angle < 2.08 {
                            deviceOrientation = .portraitUpsideDown
                        }
                    } else if z < 0 {
                        deviceOrientation = .faceUp
                    } else if z > 0 {
                        deviceOrientation = .faceDown
                    }
                } else {
                    if z > 0.875 {
                        deviceOrientation = .faceDown
                    } else if z < -0.875 {
                        deviceOrientation = .faceUp
                    } else {
                        switch deviceOrientation {
                        case .landscapeLeft:
                            if angle < -1.07 {
                                deviceOrientation = .portrait
                            }
                            if angle > 1.08 {
                                deviceOrientation = .portraitUpsideDown
                            }
                        case .landscapeRight:
                            if angle < 0 && angle > -2.05 {
                                deviceOrientation = .portrait
                            }
                            if angle > 0 && angle < 2.05 {
                                deviceOrientation = .portraitUpsideDown
                            }
                        case .portraitUpsideDown:
                            if angle > 2.66 {
                                deviceOrientation = .landscapeRight
                            }
                            if angle < 0.48 {
                                deviceOrientation = .landscapeLeft
                            }
                        case .portrait:
                            if angle > -0.47 {
                                deviceOrientation = .landscapeLeft
                            }
                            if angle < -2.64 {
                                deviceOrientation = .landscapeRight
                            }
                        default:
                            if angle > -0.47 {
                                deviceOrientation = .landscapeLeft
                            }
                            if angle < -2.64 {
                                deviceOrientation = .landscapeRight
                            }
                        }
                    }
                }
                if strongSelf.deviceOrientation != deviceOrientation {
                    strongSelf.deviceOrientation = deviceOrientation
                    strongSelf.delegate?.didChange(deviceOrientation: deviceOrientation)
                }
            }
        }
    
        func stopMeasuring() {
            motionManager.stopAccelerometerUpdates()
        }
    
        func currentInterfaceOrientation() -> AVCaptureVideoOrientation {
            switch deviceOrientation {
            case .portrait:
                return .portrait
            case .landscapeRight:
                return .landscapeLeft
            case .landscapeLeft:
                return .landscapeRight
            case .portraitUpsideDown:
                return .portraitUpsideDown
            default:
                return .portrait
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 02:48

    Handling all 6 orientations

    Though we don't often care about FaceUp / FaceDown orientations, they're still important.

    Taking them into account leads to a much more appropriate sensitivity for orientation changes, while leaving them out can lead to metastability & hysteresis.

    Here's how I handled it -

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

    Additionally, I've added a threshold value of 40.0 (instead of 45.0). This makes changes less sensitive, preventing hysteresis at inflection points.

    If you only want to react to changes of the main 4 orientations, just do this

    if (UIDeviceOrientationIsPortrait(orientation) || UIDeviceOrientationIsLandscape(orientation))
    {
         // Do something
    }
    
    0 讨论(0)
提交回复
热议问题