2013-10-02 17 views
11

Mam proste pytanie. Próbuję wykryć, kiedy użytkownik wstrząsa iPhonem. Mam standardowy kod do wykrywania ruchu i nie stanowi to problemu. Jednak podczas testowania tego na moim prawdziwym telefonie zdałem sobie sprawę, że trzeba mocno wstrząsnąć urządzeniem, aby uruchomić wykrywanie ruchu. Chciałbym wiedzieć, czy istnieje sposób na wdrożenie poziomu sprawdzania wrażliwości. Na przykład: sposób na wykrycie, czy użytkownik lekko potrząsa urządzeniem lub między lekkim a silnym wstrząsem. Będzie to skierowane na system iOS 7, więc wszelkie rady lub rady, które nie są przestarzałe w starszych wersjach systemu iOS, byłyby bardzo mile widziane. Zrobiłem swoje googlowanie, ale jeszcze nie znalazłem żadnych dobrych rozwiązań tego problemu (jeśli są jakieś).Wykrywanie ruchu iOS: Poziomy czułości wykrywania ruchu

Dzięki!

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

Odpowiedz

6

Użyj ruchu rdzenia. Połącz plik binarny ze strukturą CoreMotion. Dodaj #import do swojej klasy. Utwórz instancję CMMotionManager. Ustaw właściwość deviceMotionUpdateInterval na odpowiednią wartość. Następnie wywołaj startDeviceMotionUpdatesToQueue. Otrzymasz ciągłe aktualizacje wewnątrz bloku, które obejmuje przyspieszenie, pole magnetyczne, obrót, itp. Otrzymasz dane, które potrzebujesz. Jedną z rzeczy, którą należy się zająć, jest to, że aktualizacja będzie tak szybka, jeśli odstęp jest zbyt mały, a zatem będziesz musiał zastosować odpowiednią logikę, aby obsłużyć to samo.

+0

Dzięki temu bardzo mi pomogło, opublikuję rozwiązanie, które zaimplementowałem po twoim wpisie i inne wyszukiwanie, które doprowadziło mnie do tego samego miejsca. – zic10

+0

Cieszę się, że pomogło Ci –

+0

czy można wykryć zdarzenie shake, gdy aplikacja jest w tle –

17

Oto rozwiązanie, które znalazłem. Działa to dobrze, ale musisz grać z wartością czasu deviceMotionUpdateInterval, jak również z wartością przyspieszenia, co może być trudne do uzyskania dokładnego wyważenia dla rzeczywistego "lekkiego drgania" w porównaniu do "podniesienia telefonu i przybliżenia go do twarzy itp." ... "Mogą istnieć lepsze sposoby, ale tutaj zaczyna się. Wewnątrz mojego widoku didLoad zrobiłem coś takiego:

#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

Ta metoda motionMethod nie jest wywoływana podczas potrząsania urządzeniem – Dhara

+0

Czy dołączono application.applicationSupportsShakeToEdit = YES; w twojej metodzie didFinishLaunchingWithOptions w AppDelegate.m? – zic10

+0

wciąż nie jest wywoływana :( – harshitgupta

5

Jest to szybka wersja na podstawie odpowiedzi zic10 za, z dodatkiem flaga, która zapobiega coraz kilka dodatkowych połączeń do obsługi ruchu nawet podczas pierwszej linii w tej obsadzie jest motionManager.stopDeviceMotionUpdates().

Wartość około 3.0 może być przydatna, jeśli chcesz zignorować drgania, ale wykryć uderzenie. Zauważyłem, że 0.3 jest o wiele za nisko, ponieważ zakończyło się to bardziej jak "wykryć ruch". W swoich badaniach zakresy były bardziej:

  • 0,75 - 2,49 jest lepszy zakres czułości wytrząsania
  • 2,5 - 5,0 jest dobrym zakres „ignoruj ​​wytrząsania wykrycia guza”

Oto pełna kontroler widok na Xcode pojedynczego szablonu 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) 
    } 

} 

a ujęć użyłem do tego testu wygląda następująco:

Warto również zauważyć, że CoreMotion nie jest testowalny w symulatorze. Z powodu tego ograniczenia wciąż możesz uznać, że warto dodatkowo wdrożyć metodę wykrywania ruchu w UIDevice. Umożliwiłoby to ręczne przetestowanie wstrząsu w symulatorze lub udzielenie UITestom dostępu do wstrząsów do testowania lub narzędzi takich jak migawka Fastlana.Coś jak:

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

} 

A następnie użyj Ctrl-Cmd-Z, aby przetestować drżenie w symulatorze.

0

Herezje jak zrobiłem to za pomocą Swift 3.

importu CoreMotion i utworzyć instancję

import CoreMotion 
let motionManager = CMMotionManager() 

Na viewDidLoad lub gdziekolwiek chcesz rozpocząć sprawdzanie aktualizacji:

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

Ta funkcja przyjmuje szybkość rotacji i otrzymuje sumę za bezwzględne wartości dla ruchów x, yi 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 

}