Detecting Shaking

Apple’s shake-detection algorithm analyses eight to ten successive pairs of raw accelerometer triplet values and determines the angle between these readings. If the change in angular velocity between successive data points is large then the algorithm determines that a UIEventSubtypeMotionShake has occurred, and the motionBegan:withEvent: delegate method is called. Conversely, if the change in angular velocity is small and a shake event has been triggered, the motionEnded:withEvent: delegate method is called.

Note

The iPhone is better at detecting side-to-side rather than front-to-back or up-and-down motions. Take this into account in the design of your application.

There are three motion delegate methods, mirroring the methods for gesture handling: motionBegin:withEvent:, motionEnded:withEvent: and motionCancelled:withEvent:. The first indicates the start of a motion event, the second the end of this event. You cannot generate a new motion event for a second (or two) following the first event. The final delegate method is called when a motion is interrupted by a system event, such as an incoming phone call.

Let’s go ahead and add shake detection to our Accelerometer application. You’ll need to add another UILabel to the UI that will change depending on the motion event status. Click on the AccelerometerViewController.h interface file to open it in the Standard Editor and add another UILabel marked as an IBOutlet to the class definition:

@interface AccelerometerViewController : UIViewController <UIAccelerometerDelegate> {

    IBOutlet UILabel *xLabel;
    IBOutlet UILabel *yLabel;
    IBOutlet UILabel *zLabel;

    IBOutlet UIProgressView *xBar;
    IBOutlet UIProgressView *yBar;
    IBOutlet UIProgressView *zBar;
    IBOutlet UILabel *orientationLabel;
    IBOutlet UILabel *shakeLabel;
    IBOutlet UIImageView *arrowImage;

    UIAccelerometer *accelerometer;

}

Save your changes and click on the AccelerometerViewController.m implementation file to open it in the Xcode editor.

The easiest way to ensure that the view controller receives motion events is to promote it to First Responder in the viewDidAppear: method. Remember to make the controller resign as first responder when the view goes away. Add the viewDidAppear: method and modify the existing viewWillDisappear: method as highlighted below. Use the canBecomeFirstResponder method to indicate that the view controller can indeed become the First Responder:

- (BOOL)canBecomeFirstResponder {
    return YES;
}

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

-(void) viewWillDisappear: (BOOL) animated{
    [super viewWillDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver: self];
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [self resignFirstResponder];
}

Save your changes and click on the AccelerometerViewController.xib file for the last time. Drag-and-drop a UILabel into the View from the Object Library and connect it to the shakeLabel outlet as in Figure 4-11.

Connecting the shakeLabel outlet

Figure 4-11. Connecting the shakeLabel outlet

Save your changes and return to the AccelerometerViewController.m file in the editor, and add the following delegate methods to the implementation:

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if ( motion == UIEventSubtypeMotionShake ) {
        shakeLabel.text = @"SHAKE";
        shakeLabel.textColor = [UIColor redColor];
    }
    return;
}

- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if ( motion == UIEventSubtypeMotionShake ) {
        shakeLabel.text = @"NO SHAKE";
        shakeLabel.textColor = [UIColor greenColor];
    }
    return;
}

- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
    if ( motion == UIEventSubtypeMotionShake ) {
        shakeLabel.text = @"SHAKE CANCELLED";
        shakeLabel.textColor = [UIColor blackColor];
    }
    return;
}

Save your changes and click on the Run button in the Xcode toolbar. After the application is built and deployed to your device, try shaking the phone. You should see something very much like Figure 4-12.

Shake detection on the iPhone

Figure 4-12. Shake detection on the iPhone

Get Basic Sensors in iOS now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.