Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I detect when someone shakes an iPhone?

I want to react when somebody shakes the iPhone. I don't particularly care how they shake it, just that it was waved vigorously about for a split second. Does anyone know how to detect this?

like image 991
Josh Gagnon Avatar asked Sep 29 '08 20:09

Josh Gagnon


People also ask

What happens when you shake iPhone?

Just shake your phone to undo. While the Mac has Command-Z, the iPhone has its own unique way of fixing typing mistakes: Shake to Undo. Shaking your device to go back or undo a mistake has been around since 2009 and iOS 3 (called iPhone OS back then). And it's one of the most overlooked features on iOS.


2 Answers

In 3.0, there's now an easier way - hook into the new motion events.

The main trick is that you need to have some UIView (not UIViewController) that you want as firstResponder to receive the shake event messages. Here's the code that you can use in any UIView to get shake events:

@implementation ShakingView  - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {     if ( event.subtype == UIEventSubtypeMotionShake )     {         // Put in code here to handle shake     }      if ( [super respondsToSelector:@selector(motionEnded:withEvent:)] )         [super motionEnded:motion withEvent:event]; }  - (BOOL)canBecomeFirstResponder { return YES; }  @end 

You can easily transform any UIView (even system views) into a view that can get the shake event simply by subclassing the view with only these methods (and then selecting this new type instead of the base type in IB, or using it when allocating a view).

In the view controller, you want to set this view to become first responder:

- (void) viewWillAppear:(BOOL)animated {     [shakeView becomeFirstResponder];     [super viewWillAppear:animated]; } - (void) viewWillDisappear:(BOOL)animated {     [shakeView resignFirstResponder];     [super viewWillDisappear:animated]; } 

Don't forget that if you have other views that become first responder from user actions (like a search bar or text entry field) you'll also need to restore the shaking view first responder status when the other view resigns!

This method works even if you set applicationSupportsShakeToEdit to NO.

like image 127
Kendall Helmstetter Gelner Avatar answered Sep 19 '22 17:09

Kendall Helmstetter Gelner


From my Diceshaker application:

// Ensures the shake is strong enough on at least two axes before declaring it a shake. // "Strong enough" means "greater than a client-supplied threshold" in G's. static BOOL L0AccelerationIsShaking(UIAcceleration* last, UIAcceleration* current, double threshold) {     double         deltaX = fabs(last.x - current.x),         deltaY = fabs(last.y - current.y),         deltaZ = fabs(last.z - current.z);      return         (deltaX > threshold && deltaY > threshold) ||         (deltaX > threshold && deltaZ > threshold) ||         (deltaY > threshold && deltaZ > threshold); }  @interface L0AppDelegate : NSObject <UIApplicationDelegate> {     BOOL histeresisExcited;     UIAcceleration* lastAcceleration; }  @property(retain) UIAcceleration* lastAcceleration;  @end  @implementation L0AppDelegate  - (void)applicationDidFinishLaunching:(UIApplication *)application {     [UIAccelerometer sharedAccelerometer].delegate = self; }  - (void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {      if (self.lastAcceleration) {         if (!histeresisExcited && L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.7)) {             histeresisExcited = YES;              /* SHAKE DETECTED. DO HERE WHAT YOU WANT. */          } else if (histeresisExcited && !L0AccelerationIsShaking(self.lastAcceleration, acceleration, 0.2)) {             histeresisExcited = NO;         }     }      self.lastAcceleration = acceleration; }  // and proper @synthesize and -dealloc boilerplate code  @end 

The histeresis prevents the shake event from triggering multiple times until the user stops the shake.

like image 38
millenomi Avatar answered Sep 21 '22 17:09

millenomi