2013-10-02 18 views
11

私は簡単な質問があります。私はユーザーがiPhoneを揺するときを検出しようとしています。モーションを検出するための標準コードが用意されていますが、問題はありません。しかし、私の実際の携帯電話でこれをテストするには、動き検出をトリガするためにデバイスをかなり揺さぶらなければならないことに気付きました。私は、感度チェックのレベルを実装する方法があるかどうかを知りたいと思います。たとえば、ユーザーがデバイスを軽く振るか、光とハードの間でどこかを振るかどうかを検出する方法。これはiOS 7を対象にしていますので、古いiOSバージョンでは廃止されていないヒントやアドバイスは大変ありがとうございます。私はグーグルグーグルをやったことがありますが、まだこの問題の解決策が見つかっていません(ある場合)。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]; 
} 

答えて

6

コアモーションを使用します。 CoreMotionフレームワークにバイナリをリンクします。 #importをクラスに含めます。 CMMotionManagerのインスタンスを作成します。 deviceMotionUpdateIntervalプロパティを適切な値に設定します。 次に、startDeviceMotionUpdatesToQueueを呼び出します。 ブロック内で、加速、磁場、回転など、継続的な更新が行われます。 必要なデータが得られます。 注意すべき点の1つは、間隔が短すぎると更新が非常に速くなるため、同じ処理に適切なロジックを使用する必要があるということです。

+0

ありがとうございました。私は多くの助けになりました。私はあなたの記事と他のグーグルに続いて実装した解決策を投稿して、同じ場所に導いてくれました。 – zic10

+0

アプリがバックグラウンドであるときに揺れイベントを検出することが可能であることを –

+0

が助けてくれてうれしいです –

17

ここに私が見つけた解決策があります。これはうまくいきますが、deviceMotionUpdateIntervalの時間値とaccelerationThresholdを使って遊ぶ必要があります。これは、実際の「光の揺れ」と電話を拾って顔に近づける... "もっと良い方法があるかもしれないが、ここで始めるのが一番だ。

#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]; 
     } 
} 
+0

このメソッドは、デバイスを揺するとmotionMethodが呼び出されないようにしています – Dhara

+0

application.applicationSupportsShakeToEdit = YES; AppDelegate.mのdidFinishLaunchingWithOptionsメソッドで? – zic10

+0

まだ呼び出されていません:( – harshitgupta

5

これはあなたの運動ハンドラでも最初の行にいくつかの余分な呼び出しを取得防止のフラグを追加してzic10の回答に基づいて迅速バージョン、である:私のビューdidLoadの内部私はこのような何かをしましたそのハンドラではmotionManager.stopDeviceMotionUpdates()です。

また、振れを無視してバンプを検出したい場合は、約3.0の値を使用すると便利です。私は0.3が「検出移動」のようになってしまったので、あまりにも低すぎると感じました。私のテストでは、範囲がよりようだった:

  • 0.75から5.0「揺れを無視バンプを検出する」

のための良好な範囲である - 2.49は、振れ感度

  • 2.5のためのより良い範囲がありますここで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) 
        } 
    
    } 
    

    そして、私がこのテストに使用ストーリーボードは次のようになります。

    enter image description here

    CoreMotionがシミュレータでテスト可能でないことにも注意してください。この制約のため、モーションシェイクを検出するUIDeviceメソッドを追加実装する価値があると考えられます。これにより、シミュレータで手動でシェイクをテストしたり、UITestsにテスト用の振動やファストレーンのスナップショットのようなツールへのアクセスを与えることができます。次のようなものがあります。

    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を使用してシミュレータのシェイクをテストします。

  • 0

    相続人は、私はスウィフト3.

    インポートCoreMotionを使用してこれをしなかったとのviewDidLoadたり、アップデートのチェックを開始したい場所で

    import CoreMotion 
    let motionManager = CMMotionManager() 
    

    インスタンスを作成する方法:

    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 
    
    } 
    
    関連する問題