Swift 3设备运动重力

我有一个iPhone应用程序,其中包含一个基于设备动作调用motionmanager的gravityY参数的级别。 我已经将电平固定到手机的音高,因为我希望向用户显示手机是否相对于平面(平坦到地面)通过其x轴…从一侧到另一侧或旋转boost或下降不相关。 要做到这一点,我已经编写了应用程序,以便沿着关卡(一个条)滑动一个指示器(超出水平时红色)….它的最大行程是关卡的每一端。

该级别效果很好……并且显示正确的值,直到用户锁定手机并将其放入他或她的后袋中。 在这个阶段,水平指示器转移到水平的一端(手机的末端在口袋中boost),当手机被拉出并解锁时,应用程序不会立即恢复水平 – 它仍然存在超出水平,即使我做一个手动function调用恢复水平。 大约5分钟后,水平似乎恢复了自己。

这是代码:

func getElevation () { //now get the device orientation - want the gravity value if self.motionManager.isDeviceMotionAvailable { self.motionManager.deviceMotionUpdateInterval = 0.05 self.motionManager.startDeviceMotionUpdates( to: OperationQueue.current!, withHandler: { deviceMotion, error -> Void in var gravityValueY:Double = 0 if(error == nil) { let gravityData = self.motionManager.deviceMotion let gravityValueYRad = (gravityData!.gravity.y) gravityValueY = round(180/(.pi) * (gravityValueYRad)) self.Angle.text = "\(String(round(gravityValueY)))" } else { //handle the error self.Angle.text = "0" gravityValueY = 0 } var elevationY = gravityValueY //limit movement of bubble if elevationY > 45 { elevationY = 45 } else if elevationY < -45 { elevationY = -45 } let outofLevel: UIImage? = #imageLiteral(resourceName: "levelBubble-1") let alignLevel: UIImage? = #imageLiteral(resourceName: "levelBubbleGR-1") let highElevation:Double = 1.75 let lowElevation:Double = -1.75 if highElevation < elevationY { self.bubble.image = outofLevel } else if elevationY  Void in bubble.transform = CGAffineTransform(translationX: 0, y: CGFloat(elevationY)) }) } }) } } 

我希望水平几乎立即恢复(2-3秒内)。 我无法强制校准或更新。 这是我的第一篇文章….帮助赞赏。

编辑 – 我尝试设置一个单独的应用程序,没有任何动画,代码如下:

 // import UIKit import CoreMotion class ViewController: UIViewController { let motionManager = CMMotionManager() @IBOutlet weak var angle: UITextField! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } @IBAction func startLevel(_ sender: Any) { startLevel() } func startLevel() { //now get the device orientation - want the gravity value if self.motionManager.isDeviceMotionAvailable { self.motionManager.deviceMotionUpdateInterval = 0.1 self.motionManager.startDeviceMotionUpdates( to: OperationQueue.current!, withHandler: { deviceMotion, error -> Void in var gravityValueY:Double = 0 if(error == nil) { let gravityData = self.motionManager.deviceMotion let gravityValueYRad = (gravityData!.gravity.y) gravityValueY = round(180/(.pi) * (gravityValueYRad)) } else { //handle the error gravityValueY = 0 } self.angle.text = "(\(gravityValueY))" })} } } 

仍然表现完全相同的方式….

好的….所以我通过反复试验来解决这个问题。 首先,我构建了一个stopGravity函数,如下所示:

  func stopGravity () { if self.motionManager.isDeviceMotionAvailable { self.motionManager.stopDeviceMotionUpdates() } } 

我发现如果我调用该函数,则总是设置正确的级别,例如移动到新视图,然后在返回到原始视图时重新启动更新。 锁定设备或单击主页按钮时,我需要调用相同的function,然后在重新加载或返回视图时重新启动重力function。

为此,我在viewDidLoad()中插入以下内容…

  NotificationCenter.default.addObserver(self, selector: #selector(stopGravity), name: NSNotification.Name.UIApplicationWillResignActive, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(stopGravity), name: NSNotification.Name.UIApplicationWillTerminate, object: nil) 

这通知AppDelegate并运行该function。 这立即解决了这个问题。