【问题标题】:iOS Motion Detection: Motion Detection Sensitivity LevelsiOS 运动检测:运动检测灵敏度级别
【发布时间】:2013-10-08 13:03:09
【问题描述】:

我有一个简单的问题。我试图检测用户何时摇动 iPhone。我有标准代码来检测运动,这没有问题。然而,在我的实际手机上进行测试时,我意识到你必须非常努力地摇动设备才能触发运动检测。我想知道是否有办法实现一定程度的敏感性检查。例如,一种检测用户是否轻轻摇晃设备或介于轻摇和重摇之间的某处的方法。这将针对 iOS 7,因此任何不被旧 iOS 版本弃用的提示或建议将不胜感激。我已经完成了谷歌搜索,但还没有找到任何好的解决方案(如果有的话。)

谢谢!

-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
    if(motion == UIEventSubtypeMotionShake)
    {
       //Detected motion, do something about it 
       //at this point.
    }
}

-(BOOL)canBecomeFirstResponder
{
    return YES;
}

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    [self becomeFirstResponder];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [self resignFirstResponder];
    [super viewWillDisappear:animated];
}

【问题讨论】:

    标签: ios detection motion


    【解决方案1】:

    以下是我使用 Swift 3 的方法。

    导入 CoreMotion 并创建实例

    import CoreMotion
    let motionManager = CMMotionManager()
    

    在 ViewDidLoad 或您要开始检查更新的任何地方:

     motionManager.startDeviceMotionUpdates(to: OperationQueue.current!, withHandler:{
                deviceManager, error in
                if(error == nil){
                    if let mgr = deviceManager{
                        self.handleMotion(rate: mgr.rotationRate)
                    }
                }
            })
    

    此函数采用旋转速率并获得 x、y 和 z 运动的绝对值的总和

      func handleMotion(rate: CMRotationRate){
            let totalRotation = abs(rate.x) + abs(rate.y) + abs(rate.z)
    
            if(totalRotation > 20) {//Play around with the number 20 to find the optimal level for your case
                start()
            }else{
           print(totalRotation)
            }
        }
    
    func start(){
    
    //The function you want to trigger when the device is rotated
    
    }
    

    【讨论】:

      【解决方案2】:

      这是一个基于 zic10 答案的 swift 版本,添加了一个标志,即使该处理程序中的第一行是 motionManager.stopDeviceMotionUpdates(),也可以防止对您的运动处理程序进行一些额外的调用。

      此外,如果您想忽略抖动但检测到颠簸,3.0 附近的值可能很有用。我发现0.3 太低了,因为它最终更像是“检测移动”。在我的测试中,范围更像是:

      • 0.75 - 2.49 是更好的抖动灵敏度范围
      • 2.5 - 5.0 是“忽略抖动,检测碰撞”的理想范围

      这是 Xcode 单一 VC 模板的完整视图控制器:

      import UIKit
      import CoreMotion
      
      class ViewController: UIViewController {
      
          lazy var motionManager: CMMotionManager = {
              return CMMotionManager()
          }()
      
          let accelerationThreshold = 3.0
      
          var handlingShake = false
      
          override func viewWillAppear(animated: Bool) {
              handlingShake = false
              motionManager.startDeviceMotionUpdatesToQueue(NSOperationQueue.currentQueue()!) { [weak self] (motion, error) in
                  if
                      let userAcceleration = motion?.userAcceleration,
                      let _self = self {
      
                      print("\(userAcceleration.x) / \(userAcceleration.y)")
      
                      if (fabs(userAcceleration.x) > _self.accelerationThreshold
                          || fabs(userAcceleration.y) > _self.accelerationThreshold
                          || fabs(userAcceleration.z) > _self.accelerationThreshold)
                      {
                          if !_self.handlingShake {
                              _self.handlingShake = true
                              _self.handleShake();
                          }
                      }
      
                  } else {
                      print("Motion error: \(error)")
                  }
              }
          }
      
          override func viewWillDisappear(animated: Bool) {
              // or wherever appropriate
              motionManager.stopDeviceMotionUpdates()
          }
      
          func handleShake() {
              performSegueWithIdentifier("showShakeScreen", sender: nil)
          }
      
      }
      

      我用于此测试的情节提要如下所示:

      另外值得注意的是,CoreMotion 在模拟器中是不可测试的。由于这个限制,您可能仍然发现额外实现检测运动抖动的 UIDevice 方法是值得的。这将允许您在模拟器中手动测试摇动或让 UITests 访问摇动以进行测试或诸如 fastlane 的快照之类的工具。比如:

      class ViewController: UIViewController {
      
          override func viewDidAppear(animated: Bool) {
              super.viewDidAppear(animated)
              becomeFirstResponder()
          }
      
          override func canBecomeFirstResponder() -> Bool {
              return true
          }
      
          override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent?) {
              if TARGET_OS_SIMULATOR != 0 {
                  if event?.subtype == .MotionShake {
                      // do stuff
                  }
              }
          }
      
      }
      

      然后在模拟器中使用Ctrl-Cmd-Z测试摇晃。

      【讨论】:

        【解决方案3】:

        这是我找到的解决方案。这很好用,但你必须使用 deviceMotionUpdateInterval 时间值以及加速度阈值,这对于实际的“轻微抖动”与“拿起手机并将其靠近你的脸等”进行精细平衡可能会很棘手...” 可能有更好的方法,但这里有一个开始。在我的视图中 didLoad 我做了这样的事情:

        #import <CoreMotion/CoreMotion.h> //do not forget to link the CoreMotion framework to your project
        #define accelerationThreshold  0.30 // or whatever is appropriate - play around with different values
        
        -(void)viewDidLoad
        {
              CMMotionManager *motionManager; 
        
              motionManager = [[CMMotionManager alloc] init];
              motionManager.deviceMotionUpdateInterval = 1;
        
              [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue currentQueue]  withHandler:^(CMDeviceMotion *motion, NSError *error)
                     {
                        [self motionMethod:motion];
                     }];
        }
        
        -(void)motionMethod:(CMDeviceMotion *)deviceMotion
        {
            CMAcceleration userAcceleration = deviceMotion.userAcceleration;
            if (fabs(userAcceleration.x) > accelerationThreshold
                || fabs(userAcceleration.y) > accelerationThreshold
                || fabs(userAcceleration.z) > accelerationThreshold)
                {
                   //Motion detected, handle it with method calls or additional
                   //logic here.
                   [self foo];
                }
        }
        

        【讨论】:

        • 摇动设备时不会调用此方法motionMethod
        • 您是否包括了 application.applicationSupportsShakeToEdit = YES;在 AppDelegate.m 的 didFinishLaunchingWithOptions 方法中?
        • 需要将 CMMotionManager 实例声明为属性,以便它保留在内存中...
        【解决方案4】:

        使用核心运动。 将您的二进制文件与 CoreMotion 框架链接。 在您的课程中包含#import。 创建 CMMotionManager 的实例。 将 deviceMotionUpdateInterval 属性设置为合适的值。 然后调用 startDeviceMotionUpdatesToQueue。 您将在块内获得持续更新,包括加速度、磁场、旋转等。 您将获得所需的数据。 需要注意的一点是,如果间隔太小,更新会非常快,因此您必须使用适当的逻辑来处理。

        【讨论】:

        • 感谢这对我有很大帮助,我将在您的帖子和其他一些将我带到同一个地方的谷歌搜索之后发布我实施的解决方案。
        • 很高兴知道它对您有所帮助
        • 应用在后台时是否可以检测到抖动事件
        猜你喜欢
        • 1970-01-01
        • 2012-04-26
        • 2013-07-11
        • 1970-01-01
        • 2012-11-15
        • 1970-01-01
        • 1970-01-01
        • 2021-10-27
        • 2018-11-14
        相关资源
        最近更新 更多