There are three parts to the accelerometer equation:
UIAccelerometer Class: lets you register to receive acceleration related data from the hardware, this class is not directly created but rather accessed using a shared UIAccelerometer object.
UIAcceleration Class: this contains x, y, and z axis acceleration data (measured in G-force) as well as a relative timestamp.
UIAccelerometerDelegate Protocol: receives the acceleration related data from the system.
...and only one part to the vibrate equation... which we'll cover below.
For more information on the classes and protocols visit the iPhone Dev Center.
Skake: Using the Accelerometer
Implementing the use of the accelerometer is quite simple and only requires a few steps to start sensing the motion of your iPhone/iPod touch. In this example we’re going to use a fictitious class MainViewController.
First thing we do is add the UIAccelerometerDelegate protocol to MainViewController.h allowing the class to respond to acceleration related data sent from the device. Also, note that UIAccelerometer is part of the UIKit Framework.
#import <UIKit/UIKit.h> @interface MainViewController : UIViewController <UIAccelerometerDelegate> { } @end
The UIAccelerometerDelegate protocol only has only has one instance method which delivers acceleration data to the delegate (which we’ll add to the implementation file):
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration;
As the accelerometer is a shared object and is constantly updated I like to add on/off methods to my class so that I can control when the updates are handled. For example you might want the acceleration to only happen when the view controller is visible.
Also, as the information sent from the UIAcceleration delegate is a stream of data updated at a defined interval I want to be able to create a threshold (minimum) before acting upon the data. I add this in the method itself, but you could create a #define for each of the three axis. Also, I’d like to point out that this is not complete code as you will still need to implement your view, init, etc, and this covers adding functionality.
Let’s add the methods and definition to our implementation file (MainViewController.m):
#import "MainViewController.h" @interface MainViewController () - (void)startAccelerometer; - (void)stopAccelerometer; @end @implementation MainViewController - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { double const kThreshold = 2.0; if ( fabsf(acceleration.x) > kThreshold || fabsf(acceleration.y) > kThreshold || fabsf(acceleration.z) > kThreshold) { NSLog(@"Hey, stop shaking me!"); } } - (void)startAccelerometer { UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.delegate = self; accelerometer.updateInterval = 0.25; } - (void)stopAccelerometer { UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer]; accelerometer.delegate = nil; } - (void)viewDidAppear:(BOOL)animated { [self startAccelerometer]; } - (void)viewWillDisappear:(BOOL)animated { [self stopAccelerometer]; } @end
That’s it. Simple. When viewDidAppear is called it calls startAccelerometer and we can start listening for acceleration related data. If the data is above 2g then we log a message. When viewWillDisappear is called it calls stopAccelerometer and we nil out our delegate and we stop listening for the accelerometer data.
Rattle: Vibrate
To make the device vibrate we need to use the AudioToolbox Framework. You may be asking why audio, and that is a good question but don’t have a solid answer. I only know how to make it work and that’s the key.
Import the AudioToolbox into the MainViewController.m file and add a declaration and method:
#import "MainViewController.h" #import <AudioToolbox/AudioToolbox.h> @interface MainViewController () - (void)vibrate; @end @implementation MainViewController - (void)vibrate { AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); } @end
That’s it. And it’s simpler than dealing with the shaking of the accelerometer. Just one line of code (more or less) and you have vibrating in your app.
Roll: Combining Accelerometer and Vibrate
What I like to do is add the vibrate method to the accelerometer:didAccelerate: method so that when user shakes their device it fires off the vibration to give haptic feedback of the action.
All you need to do is modify the accelerometer:didAccelerate: method:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { double const kThreshold = 2.0; if ( fabsf(acceleration.x) > kThreshold || fabsf(acceleration.y) > kThreshold || fabsf(acceleration.z) > kThreshold) { [self vibrate]; } }
Now when you shake the device, it vibrates. Simple to implement and good user feedback.
We first implement this in our kids' application Fridgemags and I have to say that kids like shaking the device and feeling it vibrate. We also move colored alphabet letters around the screen and make a whooshing sound of sorts to engage the kids and keeps them busy for a good amount of time.