即使设备方向锁定,也可获取当前iOS设备的方向

17

即使设备方向被锁定,我想获取当前的iOS设备方向。(就像iOS相机应用程序)

我至少要检测肖像、左横和右横。

在方向被锁定时,UIDeviceOrientation和UIInterfaceOrientation似乎不起作用。

在这种情况下,我认为我们将使用CoreMotion。

我该如何在Swift4中实现它?


你尝试过这个答案吗? - nayem
感谢回复。是的,但这并没有解决问题。即使设备放在桌子上,方向也不稳定... - okd
对于将设备放置在__桌子__上,您需要考虑z轴。虽然该答案没有完成,但留下了关于朝上和朝下的线索。 - nayem
谢谢。我试一下。 - okd
3个回答

34

使用Core Motion声明运动管理器

    var orientationLast = UIInterfaceOrientation(rawValue: 0)!
    var motionManager: CMMotionManager?

动画管理器初始化

并在 viewDidLoad 中调用此函数。

    func initializeMotionManager() {
     motionManager = CMMotionManager()
     motionManager?.accelerometerUpdateInterval = 0.2
     motionManager?.gyroUpdateInterval = 0.2
     motionManager?.startAccelerometerUpdates(to: (OperationQueue.current)!, withHandler: {
        (accelerometerData, error) -> Void in
        if error == nil {
            self.outputAccelerationData((accelerometerData?.acceleration)!)
        }
        else {
            print("\(error!)")
        }
        })
     }   

分析加速度计数据

 func outputAccelerationData(_ acceleration: CMAcceleration) {
    var orientationNew: UIInterfaceOrientation
    if acceleration.x >= 0.75 {
        orientationNew = .landscapeLeft
        print("landscapeLeft")
    }
    else if acceleration.x <= -0.75 {
        orientationNew = .landscapeRight
        print("landscapeRight")
    }
    else if acceleration.y <= -0.75 {
        orientationNew = .portrait
        print("portrait")
        
    }
    else if acceleration.y >= 0.75 {
        orientationNew = .portraitUpsideDown
        print("portraitUpsideDown")
    }
    else {
        // Consider same as last time
        return
    }
    
    if orientationNew == orientationLast {
        return
    }
    orientationLast = orientationNew
}

太棒了!非常好的答案。 - Rotem
您,先生,是一个传奇。谢谢! - Christian Bringino
有人可以解释一下为什么在这种情况下要使用0.75吗? - Tedxxxx
1
很好的答案。然而,landscapeLeftlandscapeRight是相反的。 - nrj
1
@nrj 在那个解决方案中,Thomas 考虑了 UIInterfaceOrientation,而不是设备方向。 如果您查看 UIInterfaceOrientation 的文档,您会看到这个注释:“请注意,UIInterfaceOrientationLandscapeLeft 等于 UIDeviceOrientationLandscapeRight(反之亦然)。这是因为将设备向左旋转需要将内容向右旋转。” - Frederic Adda
显示剩余5条评论

8

Swift 5

Declaration

var motionManager   : CMMotionManager!

初始化

func addCoreMotion() {

    let splitAngle:Double = 0.75
    let updateTimer:TimeInterval = 0.5

    motionManager = CMMotionManager()
    motionManager?.gyroUpdateInterval = updateTimer
    motionManager?.accelerometerUpdateInterval = updateTimer

    var orientationLast    = UIInterfaceOrientation(rawValue: 0)!

    motionManager?.startAccelerometerUpdates(to: (OperationQueue.current)!, withHandler: {
        (acceleroMeterData, error) -> Void in
        if error == nil {

            let acceleration = (acceleroMeterData?.acceleration)!
            var orientationNew = UIInterfaceOrientation(rawValue: 0)!

            if acceleration.x >= splitAngle {
                orientationNew = .landscapeLeft
            }
            else if acceleration.x <= -(splitAngle) {
                orientationNew = .landscapeRight
            }
            else if acceleration.y <= -(splitAngle) {
                orientationNew = .portrait
            }
            else if acceleration.y >= splitAngle {
                orientationNew = .portraitUpsideDown
            }

            if orientationNew != orientationLast && orientationNew != .unknown{
                orientationLast = orientationNew
                self.deviceOrientationChanged(orinetation: orientationNew)
            }
        }
        else {
            print("error : \(error!)")
        }
    })
}

结果

 func deviceOrientationChanged(orinetation:UIInterfaceOrientation) {

      print("orinetation :",orinetation.rawValue)
     // updatYourUI or another stuff

 }

0
这是一个检测设备旋转并返回UIDeviceOrientation的示例。 此解决方案使用CoreMotion,在所有情况下都有效。
示例:
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

符合委托

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

APOrientationManager.swift

import Foundation
import CoreMotion
import AVFoundation

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接