Question

I have a UIView that I want to always be facing up. So say you have an UIImageView that has an arrow, and no matter what way the device is being held, it's pointing up. Obviously I need the accelerometer, but telling it to rotate the image based on the coordinates is only going to work the first time I think, since rotations are relative. Is there an easier way of doing this? I feel like there would be a simple example app somewhere that would do something like this.

Was it helpful?

Solution

Apple has sample code which does exactly what you want; have a look at this: http://developer.apple.com/library/ios/#samplecode/WhichWayIsUp/Introduction/Intro.html

To receive specific motion data, use the shared instance of UIAccelerometer and it's delegate. http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIAccelerometerDelegate_Protocol/UIAccelerometerDelegate/UIAccelerometerDelegate.html#//apple_ref/occ/intf/UIAccelerometerDelegate

As far as the rotations, I'm not sure. Have a look at the "BubbleLevel" sample code here: http://developer.apple.com/library/ios/samplecode/BubbleLevel/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007331

The accelerometer delegate documentation references that and other relevant sample code.

OTHER TIPS

WhichWayIsUp is the sample application you're looking for - in iOS Reference Library (great docs!)

Transforms applied to a view aren’t cumulative. Rather, the view starts out being aligned to the coordinate system of its parent, and the transform is applied relative to that.

As other answers have alluded to, there are enough pieces in Apple’s BubbleLevel sample code to accomplish what you’re looking for. -[LevelViewController accelerometer:didAccelerate:] already contains an example of how to extract the smoothed screen-relative rotation component of the gravity vector:

// Use a basic low-pass filter to only keep the gravity in the accelerometer values for the X and Y axes
accelerationX = acceleration.x * kFilteringFactor + accelerationX * (1.0 - kFilteringFactor);
accelerationY = acceleration.y * kFilteringFactor + accelerationY * (1.0 - kFilteringFactor);

// keep the raw reading, to use during calibrations
currentRawReading = atan2(accelerationY, accelerationX);

Given the coordinate systems of UIAcceleration and atan2, there are a few factors you’ll need to keep in mind to calculate your view’s desired rotation:

  1. When the device is upright in portrait, atan2 will return -π/2 (-90°), since the input gravity vector is {0.0, -1.0, 0.0}.
  2. CGAffineTransformMakeRotation creates a transform that will rotate clockwise (on iOS) by the specified number of radians, but the raw angle from atan2 specifies a counterclockwise rotation.

Accordingly, you’ll want to rotate your view by -(currentRawReading + π/2), assuming its parent view is oriented with the screen in portrait:

view.transform = CGAffineTransformMakeRotation(-(currentRawReading + M_PI/2));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top