2013-10-02 19 views
11

Ho una domanda semplice. Sto cercando di rilevare quando un utente scuote l'iPhone. Ho il codice standard in atto per rilevare il movimento e questo non ha alcun problema. Tuttavia, nel testare questo sul mio telefono reale, ho capito che devi scuotere il dispositivo abbastanza forte da far scattare il rilevamento del movimento. Vorrei sapere se esiste un modo per implementare un livello di controllo della sensibilità. Ad esempio, un modo per rilevare se un utente scuote leggermente il dispositivo o da qualche parte tra luce e tremolio. Questo sarà indirizzato a iOS 7, quindi qualsiasi suggerimento o consiglio che non sia deprecato dalla versione iOS precedente sarebbe molto apprezzato. Ho fatto la mia ricerca su Google, ma non ho ancora trovato alcuna soluzione valida a questo problema (se ce ne sono.)Rilevamento movimento iOS: Livelli di sensibilità rilevamento movimento

Grazie!

-(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]; 
} 

risposta

6

Utilizzare movimento centrale. Collega il tuo file binario con il framework CoreMotion. Includi #import nella tua classe. Creare un'istanza di CMMotionManager. Impostare la proprietà deviceMotionUpdateInterval su un valore adatto. Quindi chiamare startDeviceMotionUpdatesToQueue. Otterrete aggiornamenti continui all'interno del blocco, che include accelerazione, campo magnetico, rotazione, ecc. Otterrete i dati richiesti. Una cosa da tenere in considerazione è che l'aggiornamento deve essere così rapido se l'intervallo è troppo piccolo, e quindi si dovrà impiegare una logica adeguata per gestire lo stesso.

+0

Grazie a questo mi ha aiutato molto, pubblicherò una soluzione che ho implementato seguendo il tuo post e qualche altro googling che mi ha portato nello stesso posto. – zic10

+0

Felice di sapere che ti ha aiutato –

+0

è possibile rilevare l'evento di scossa quando l'app è in background –

17

Ecco la soluzione che ho trovato. Funziona bene, ma devi giocare con il valore di tempo deviceMotionUpdateInterval e con l'accelerationThreshold che può essere difficile per ottenere un buon bilanciamento per un vero "light shake" vs "sollevare il telefono e spostarlo più vicino alla tua faccia, ecc. ... "Potrebbero esserci modi migliori ma qui ce n'è uno da iniziare. All'interno del mio punto di vista didLoad ho fatto qualcosa di simile:

#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

Questo metodo motionMethod non viene chiamato su scuotere il dispositivo – Dhara

+0

Hai incluso application.applicationSupportsShakeToEdit = YES; nel tuo metodo didFinishLaunchingWithOptions in AppDelegate.m? – zic10

+0

ancora senza nome :( – harshitgupta

5

Questa è una versione veloce in base alla risposta del zic10, con l'aggiunta di un flag che impedisce ottenere un paio di chiamate aggiuntive al vostro gestore di movimento anche quando la prima linea in quel gestore è motionManager.stopDeviceMotionUpdates().

Inoltre, un valore di circa 3.0 può essere utile se si desidera ignorare la scossa, ma rilevare un rilievo. Ho trovato il 0.3 troppo basso perché è diventato più simile a "rileva movimento". Nel mio test, gli intervalli erano più come:

  • 0,75 - 2.49 è l'assortimento migliore per la sensibilità scossa
  • 2,5-5,0 è una buona gamma per "ignorare shake, rilevare urto"

Ecco il controller della vista completa per un unico modello di VC Xcode:

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

} 

E lo storyboard che ho usato per questo test si presenta così:

enter image description here

Vale anche la pena notare che CoreMotion non è testabile nel simulatore. A causa di questo vincolo, potresti comunque trovare utile implementare ulteriormente il metodo UID per rilevare il movimento del movimento. Ciò consentirebbe di testare manualmente il micromosso nel simulatore o di consentire a UITests di scuotere per testare o strumenti come lo snapshot di fastlane.Qualcosa di simile:

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

} 

e quindi utilizzare Ctrl-Cmd-Z per testare scossa nel simulatore.

0

Ecco come ho fatto questo utilizzando Swift 3.

Importa CoreMotion e creare un'istanza

import CoreMotion 
let motionManager = CMMotionManager() 

On viewDidLoad o dove si desidera avviare la ricerca degli aggiornamenti:

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

Questa funzione prende la velocità di rotazione e ottiene una somma per i valori assoluti per i movimenti x, yez

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 

}