iOS device orientation disregarding orientation lock

后端 未结 10 1246
天涯浪人
天涯浪人 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:22

    Set up your view controller or whatever to support the UIAccelerometerProtocol, and start listening for changes (you can set it to 10 hz).

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

    You need to define UIInterfaceOrientation orientationLast as a member variable and you're set.

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

    The UIAccelerometer class continues to function when the device orientation is locked. You'll have to work out your own methods of turning its variables into orientation values, but it shouldn't be especially complicated.

    Have a play with Apple's AcceleromoterGraph sample app to see what values the accelerometer outputs in different orientations.

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

    Most of the answers are using accelerometer, which is the overall acceleration = user + gravity.

    But to get a device orientation, it is more accurate to use the gravity acceleration. Using gravity will prevent the edge case when user moves in a particular direction. To access the gravity, we have to use startDeviceMotionUpdates API instead.

    let motionManager = CMMotionManager()
    motionManager.startDeviceMotionUpdates(to: OperationQueue()) { (data, error) in
        guard let gravity = data?.gravity else { return }
    
        let newDeviceOrientation: UIDeviceOrientation
        if abs(gravity.y) < abs(gravity.x) {
            newDeviceOrientation = gravity.x > 0 ? .landscapeRight : .landscapeLeft
        } else {
            newDeviceOrientation = gravity.y > 0 ? .portraitUpsideDown : .portrait
        }
    }
    
    0 讨论(0)
  • 2020-11-29 02:33

    Also you can use CoreMotion

    Orientation detection algorithm:

    • if abs( y ) < abs( x ) your iPhone is in landscape position, look sign of x to detect right or left

    • else your iPhone is in portrait position, look sign of y to detect up or upside-down.

    • If you are interested in face-up or down, look value of z.


    import CoreMotion
    

    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()
    }
    
    0 讨论(0)
  • 2020-11-29 02:42

    Use of CMMotionManager may help, but not the above way. The above logic is not a stable one. I have tested throughly and found that by seeing the values of acceleration.x/y/z are not helping to determine the orientation.

    Instead, I got a way to find the orientation WRT the angle i.e. float angle = (atan2(accelerometerData.acceleration.y,accelerometerData.acceleration.x))*180/M_PI;

    And for orientation,- if(fabs(angle<=45)currOrientation=UIDeviceOrientationLandscapeRight; else if((fabs(angle)>45)&&(fabs(angle)<135))currOrientation=((angle>0)?UIDeviceOrientationPortraitUpsideDown:UIDeviceOrientationPortrait); else currOrientation = UIDeviceOrientationLandscapeLeft;

    This might come handy for someone, though this doesn't help me to find 2 other orientations i.e. UIDeviceOrientationFaceUp & UIDeviceOrientationFaceDown.

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

    Using Satachito's great answer here is code which will also detect if the device is face up or face down

    import CoreMotion
    

    var mm: CMMotionManager!
    
    init() {
        self.mm = CMMotionManager()
        self.mm.accelerometerUpdateInterval = 0.2
    }
    
    public func startOrientationUpdates() {
        //  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.
        self.mm.startAccelerometerUpdates( to: OperationQueue() ) { p, _ in
            if let p = p {
                if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z < -0.95) {
                    print("face up")
                }
                else if(p.acceleration.x > -0.3 && p.acceleration.x < 0.3 && p.acceleration.z > 0.95) {
                    print("face down")
                }
                else {
                    print(
                        abs( p.acceleration.y ) < abs( p.acceleration.x )
                            ?   p.acceleration.x > 0 ? "Right"  :   "Left"
                            :   p.acceleration.y > 0 ? "Down"   :   "Up"
                    )
                }
    
            }
        }
    }
    
    public func endOrientationUpdates() {
        self.mm.stopAccelerometerUpdates()
    }
    
    0 讨论(0)
提交回复
热议问题