The Accelerometer CSE 391 Fall 2011 Tony Scarlatos The Three Axes on the iPhone Example Values: Portrait X = 0.0 Z = 0.0 Y = - 1.0 (gravity) Example Values: Landscape Right X = 1.0 (negative if landscape left) Y = 0.0 Z = 0.0 Example Values: Tilt 45 degrees X & Y X = 0.5 Z = 0.0 Y = - 0.5 Example Values: Tilt 45 degrees Y & Z X = 0.0 Z = - 0.5 Y = - 0.5 Uses for accelerometer values • Detect orientation change – Ex. Portrait to Landscape • Detect a “Shake” – Often used to clear fields or undo an action • Use the Accelerometer as a control – Commonly used in games Detecting and Managing Orientation • If you want your interface to adapt to different orientations, such as rotating from portrait to landscape, you’ll have to edit the shouldAutorotateToInterfaceOrientation method in your view controller to be specific about which orientations you want to support. • In the code that follows on the next slide, the supported orientations are Portrait, LandscapeLeft and LandscapeRight. • In the simulator you can change orientations from the Hardware drop down menu. The shouldAutorotateToInterfaceOrientation method // Override to allow orientations other than the default portrait orientation. - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrien tation { // Return YES for supported orientations if (interfaceOrientation == UIInterfaceOrientationPortrait || //two vertical lines denote an OR statement interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) return YES; else { return NO; } } Locking out an orientation It seems like this is a good place to remind you of the code we used to force the app into landscape mode in an earlier demo: -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { if ((interfaceOrientation==UIInterfaceOrientationPortrait)||(interfaceOrientation==UIInterfaceOrientationPort raitUpsideDown)) // NO locks out the portrait mode of the iPhone. The initial landscape orientation is also set in the summary panel for the app target. { return NO; } if ((interfaceOrientation==UIInterfaceOrientationLandscapeLeft)||(interfaceOrientation==UIInterfaceOrientat ionLandscapeRight)) { return YES; } } Interface Builder Autosizing Panel If you want to compensate for the changes to your interface because of supporting multiple orientations, you can select those UI elements in IB, and in the Autosizing tab of the Inspector panel you can adjust their properties. You can choose which sides of the frame you want anchor the element to (struts), or if you want the element to stretch to fit the new orientation (springs). Interface Builder Autosizing Panel Origin establishes the location of the element in the view Fields for entering discrete values for size and position of the UI element STRUTS connect The UI element to the sides of the view (upper left corner is the default) The preview window shows the effects of your changes to the UI element SPRINGS stretch The UI element to the sides of the view Detecting a Motion Event (Shake) • The first thing to do to detect a motion event is to declare that the view controller can be the first responder. • The next thing to do is activate that status using the viewDidAppear method. • Then you can respond to either the motionBegan or motionEnded methods (or both). • You can test the event in the simulator in the Hardware drop down menu which simulates a shake event. • The code is written in the implementation file of the view controller, and it simply changes the background color of the view when the phone is shaken. It follows on the next slide. The Shake Event - (BOOL)canBecomeFirstResponder { return YES; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self becomeFirstResponder]; } - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { if (event.subtype == UIEventSubtypeMotionShake) { self.view.backgroundColor = [UIColor redColor]; } } Accessing Accelerometer data • The UIAccelerometer object contains the combined data from the 3 sensors (axes) on the iPhone. • It is a “singleton” object – it always exists. You don’t have to create or release it, you just need to request it. • The method used to access the data is sharedAccelerometer. Typically you set the delegate of the object to your view controller (self). • The other thing that you will need to set is the sampling rate using the updateInterval method. A typical sampling rate is 30 times per second. • You can then use the data in your app by employing the didAccelerate method. • In the code that follows on the next 3 slides we set up a View-based Application that displays accelerometer data in three labels and three progress bars. The mainViewController.h file @interface MainViewController : UIViewController <UIAccelerometerDelegate> { IBOutlet UILabel *labelX; IBOutlet UILabel *labelY; IBOutlet UILabel *labelZ; IBOutlet UIProgressView *progressX; IBOutlet UIProgressView *progressY; IBOutlet UIProgressView *progressZ; UIAccelerometer *accelerometer; } @property (nonatomic, retain) IBOutlet UILabel *labelX; @property (nonatomic, retain) IBOutlet UILabel *labelY; @property (nonatomic, retain) IBOutlet UILabel *labelZ; @property (nonatomic, retain) IBOutlet UIProgressView *progressX; @property (nonatomic, retain) IBOutlet UIProgressView *progressY; @property (nonatomic, retain) IBOutlet UIProgressView *progressZ; @property (nonatomic, retain) UIAccelerometer *accelerometer; The mainViewController.m file (1) @synthesize labelX; @synthesize labelY; @synthesize labelZ; @synthesize progressX; @synthesize progressY; @synthesize progressZ; @synthesize accelerometer; The mainViewController.m file (2) - (void)viewDidLoad { [super viewDidLoad]; self.accelerometer = [UIAccelerometer sharedAccelerometer]; self.accelerometer.updateInterval = .1; self.accelerometer.delegate = self; } - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { labelX.text = [NSString stringWithFormat:@"%@%f", @"X: ", acceleration.x]; labelY.text = [NSString stringWithFormat:@"%@%f", @"Y: ", acceleration.y]; labelZ.text = [NSString stringWithFormat:@"%@%f", @"Z: ", acceleration.z]; self.progressX.progress = ABS(acceleration.x); self.progressY.progress = ABS(acceleration.y); self.progressZ.progress = ABS(acceleration.z); } Testing the accelerometer app • The iPhone simulator does not natively support data from the accelerometer, but there are a couple of plug-ins for Xcode that allow your device to send that information to the simulator wirelessly. • The free app, AccSim, is available on the App Store. The files it depends upon (which have to be added to your Xcode project) are available at: http://www.brianhpratt.net/cms/index.php?page=accsim • A more robust app that also shares location and touch event data with the simluator is iSimulate. It’s available on the App Store for $15.99. It has a library which has to be embedded in your Xcode project that is available here: http://www.vimov.com/isimulate/sdk/ • The advantage of both of these apps is that you don’t have to install your project on your device to be able to test your code. They also provide a convenient way to make video trailers of your apps that use accelerometer input, like games.