February 24, 2012

How to Handle Device Rotation for UIViews in iOS

Choosing to support orientation changes in a UIViewController is a simple process in iOS. Apple has already provided the methods to attach to. Supporting orientation changes in a UIView is easy, though it is less robust. When listening for orientation changes, the view can respond visually to the rotation of the device. These notifications will also notify when the device is screen-side down or screen-side up.

Illustration of an iPhone rotating in space to show device orientation with a green arrow and a crazy photo of me in the February 2011 Chicago blizzard as the wallpaper

Requesting Notifications for Orientation Changes

Code to support orientation changes can be added at any time throughout the life of a view. The code to start listening for notifications of orientation changes is:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver: self selector:@selector(deviceOrientationDidChange:) name: UIDeviceOrientationDidChangeNotification object:nil];

UIDevice according to the Apple documentation is “a singleton instance representing the current device.” Calling the class method1beginGeneratingDeviceOrientationNotifications tells the device to fire up the accelerometer to start sending out orientation change notifications. However that one line alone will not respond to the notifications. The second line will and adds the view (self) as an observer to the main notification center. It will then start receiving notifications of type UIDeviceOrientationDidChangeNotification. Each time the orientation changes the method, via @selector, will call our custom method deviceOrientationDidChange:. The colon representing a parameter will be a variable of type NSNotification.

Responding to Device Rotation

Using the code above, the view is ready to respond with the following method.

UIDeviceOrientation currentOrientation;

- (void)deviceOrientationDidChange:(NSNotification *)notification {
//Obtaining the current device orientation
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

//Ignoring specific orientations
if (orientation == UIDeviceOrientationFaceUp || orientation == UIDeviceOrientationFaceDown || orientation == UIDeviceOrientationUnknown || currentOrientation == orientation) {
return;
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(relayoutLayers)object:nil];
//Responding only to changes in landscape or portrait
currentOrientation = orientation;
//
[self performSelector:@selector(orientationChangedMethod) withObject:nil afterDelay:0];
}

The first line sets up currentOrientation to hold the last orientation. A lot of data comes through and the slightest movement can trigger another notification. So to prevent unnecessary reaction, the last orientation is stored.

The method is the one mentioned above and takes the parameter of the typeNSNotification. Then the current device orientation is stored in a local variable.

Using orientation, specific orientations are ignored. I only want the app to respond to rotation changes from portrait to landscape. So we check to make sure the orientation is not changing to face up or face down. The device can have issues determining the orientation. This is why it will also ignore the unknown (UIDeviceOrientationUnknown) notification. Finally, if the last orientation was the same (to avoid unnecessary rotation code execution); ignored.

Now that the orientation is not face up, face down, unknown, or the same as the last event, the currentOrientation variable is set. The last line of the method performs a @selector. This will call another method with optional parameters after a specified amount of time. This is necessary because any changes based on the bounds of the view (self) will not be updated by the time this method has been called.

Extra Orientation Notes

After implementing the code above in my own view, there were times when the device rotated 180 degrees so the orientation change was handled by the parentUIViewController. Therefore the updates I was doing in myorientationChangedMethod were unnecessary. The following code was added to check for similar orientations and return if no change was needed.

if ((UIDeviceOrientationIsPortrait(currentOrientation) &&UIDeviceOrientationIsPortrait(orientation)) ||
(UIDeviceOrientationIsLandscape(currentOrientation) &&UIDeviceOrientationIsLandscape(orientation))) {
//still saving the current orientation
currentOrientation = orientation;
return;
}

If the view implementing this code requires actions based on an orientation, it is recommended to base it on the default orientation UIDeviceOrientationPortrait orUIDeviceOrientationLandscape, based on the need for your app. Otherwise the default value for [[UIDevice currentDevice] orientation] isUIDeviceOrientationUnknown and can lead to unexpected results if code depends on this orientation being correct.


source from http://the.ichibod.com/kiji/how-to-handle-device-rotation-for-uiviews-in-ios/

0 Comment:

Post a Comment

Để chất lượng các bài viết ngày được tốt hơn, Bạn vui lòng để lại góp ý hoặc nhận xét vào khung bên dưới. Bạn có thể tự do nhận xét nhưng không trái với thuần phong mỹ tục. Khi gửi nhận xét xin vui lòng để lại: Tên, Địa chỉ mail hoặc địa chỉ Blog để tôi được biết bạn là ai. Xin cảm ơn!

Các bài liên quan




Recent Comments

Xã hội - VnExpress.net