iOS5, iOS6, rotation, event firing arbitrarily - ios

I have an app that supports orientation changes and rotates accordingly. I listen to the event UIApplicationWillChangeStatusBarOrientationNotification. Now during the load of this app I add some views and set them up in my app, based on the current orientation.
in iOS 6, this works fine and the app responds and rotates properly, so the user can load in both landscape and portrait mode and code works fine.
in iOS 5, if I load the app in portrait mode, the app works fine, and once that load has been completed in portrait mode, and the UI is aligned and sized, it will respond to other orientation changes to landascape or portrait. The problem I have is this : When loading iOS 5 in landscape mode, and while physically laying the device with iOS 5 on a flat surface to ensure its landscape, I get a OrientationNotification that moves from Landscape to portrait ( although the device didn't change ).
So another device iOS 6 in the same experiment, loads properly and I don't get any weird events of rotation changes that didn't occur, but with iOS 5 I do get them!!
Any ideas?
I am supporting the orientation for both iOS's
- (BOOL)shouldAutorotate {
return YES;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

It sounds like iOS 5 believes things should be portrait if, in fact, there is no physical orientation (i.e. flat up or down) and iOS 6 doesn't. For what it might be worth, to determine the orientation to display stuff when it matters, I use the actual device orientation when available and the status bar orientation when the device is flat. For instance:
// Get a useful screen orientation.
// If the device is physically in portrait or landscape then
// that is the orientation.
// If it is not, then it is probably flat on a table and use
// the orientation of the status bar which should be set to
// the last physical orientation.
//
// screen Orientation
//------------------------------------------------------------
+ (UIDeviceOrientation) screenOrientation {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation!=UIInterfaceOrientationPortrait
&& orientation!=UIInterfaceOrientationPortraitUpsideDown
&& orientation!=UIInterfaceOrientationLandscapeLeft
&& orientation != UIInterfaceOrientationLandscapeRight) {
// Not known at this time. Use the status bar orientation
orientation = [[UIApplication sharedApplication] statusBarOrientation];
}
return orientation;
}
I'm not sure that helps you directly, but perhaps in your notification handler you could check to see what the actual status bar orientation is. Or maybe the timing of the notification and the status-bar orientation change doesn't make that work.

Related

iOS Getting initial device orientation with accelerometer

I am working in an OpenGL ES game, c++ and iOS. I would like that the canvas axes be always as in default portait orientation, and also be able to know which is the initial device orientation and all the orientation changes.
The problem I have is that if I configure the XCode project to support the 4 orientations: 2 Portraits and 2 Landscapes, then the Frame which is embedded the OpenGL canvas has the axes depending the initial orientation. If I configure the project to support only Portrait Orientation, then the Application won't tell me if it is in Landscape.
I would like to find a way to do this as much programmatically as possible.
1) To Know programatically in iOS
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if(orientation == UIDeviceOrientationLandscapeLeft)
landscapeRight = false;
else if(orientation == UIDeviceOrientationLandscapeRight)
else if(orientation == UIDeviceOrientationPortraitUpsideDown)
else if(orientation == UIDeviceOrientationPortrait)
....
2) For Default portrait view
Restrict other orientations in your Xcode project's info.plist

iPad shows at portrait but thinks it's landscape

My Storybuilder is designed with a portrait layout. When I start the app with my iPad already turned to horizontal, it's able to correctly detect it's in a horizontal position. But when I start the app with my iPad in a portrait position, it thinks it's in horizontal. However, every time I rotate it, the code is able to detect the correct orientation properly.
- (void) viewDidLoad
{
[self updateForOrientation];
}
- (void)updateForOrientation
{
if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) // became portrait
{
NSLog(#"is portrait");
//code for changing layout to portrait position
}
else //became horiztontal
{
NSLog(#"is horizontal");
//code for changing layout to horizontal position
}
}
Output: is horizontal (this is the output whether it starts up as portrait or landscape)
The problem is that you're sending the devices orientation in terms of the UIDeviceOrientation enum to a function that's expecting a UIInterfaceOrientation value.
If you command click on UIInterfaceOrientationIsPortrait(), you can see that it is defined as follows.
#define UIInterfaceOrientationIsPortrait(orientation) ((orientation) == UIInterfaceOrientationPortrait || (orientation) == UIInterfaceOrientationPortraitUpsideDown)
And if you look at the enum declarations for the two orientation types (documentation links below), you can see that there is a misalignment in value due to the device orientation containing a value for "none". Anyway, changing your code to use UIInterfaceOrientation should sort this out. Example:
- (void)updateForOrientation
{
UIInterfaceOrientation currentOrientation = self.interfaceOrientation;
if (UIInterfaceOrientationIsPortrait(currentOrientation)) {
NSLog(#"is portrait");
}else{
NSLog(#"is horizontal");
}
}
https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html#//apple_ref/doc/c_ref/UIInterfaceOrientation
https://developer.apple.com/library/ios/documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html#//apple_ref/doc/c_ref/UIDeviceOrientation

How to change the device orientation to portrait when the current orientation is faceup or facedown

Is there a possible way to autorotate the device orientation to portrait when the current orientation of the device is faceup or facedown?
You can use this trick to make the system refresh your controller orientation anytime you want:
[self presentViewController:[UIViewController new] animated:NO completion:NULL];
[self dismissViewControllerAnimated:NO completion:NULL];
This will call supportedInterfaceOrientations on your controller.
Just return UIInterfaceOrientationMaskPortrait when the device orientation is facing up or down and your controller's view will get adjusted accordingly.
Observe UIDeviceOrientationDidChangeNotifications to use the trick when you receive the notification and it's a face up/down device orientation, as those orientation do not correspond to UIInterfaceOrientations (and won't trigger supportedInterfaceOrientations).
Device and interface orientation definitions:
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
};
typedef NS_ENUM(NSInteger, UIDeviceOrientation) {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom
UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top
UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right
UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left
UIDeviceOrientationFaceUp, // Device oriented flat, face up
UIDeviceOrientationFaceDown // Device oriented flat, face down
};
You don't change the orientation. Instead, you tell iOS which orientations you support, so when the user rotates the device, iOS will switch the UI orientation to one that your application supports. The UI orientation should only change when the user rotates the device.
Use this code in your - (void)viewWillApper method
if(self.interfaceOrientation==UIInterfaceOrientationPortrait||self.interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown)
{
//do something;
}
else
{
}
You can disable or enable rotation of the screen in portrait mode by set an appropriate value in the project settings (Targets -> General -> Deployment Info section).
mark the Portrait checkbox
mark the Upside Down checkbox (this enable Upside Down animation)
or
mark the Portrait checkbox
unmark the Upside Down checkbox (this is only Upside mode)
Use self.view.window?.windowScene?.interfaceOrientation.
This value will be either portrait, portraitUpsideDown, landscapeRight, or landscapeLeft.
See here for documentation.

iPad stop screen from Rotating Xcode 4

I am building an iPad app in Xcode 4. The app is suposed to always show in Landscape view. to achieve this I have tried the following:
In the Target summary screen I selecte only Landscape Left as a Supported Device Orentation.
In the Target Info screen / Info.plist set the Supported interface orientations(iPad) to Landscape (left home button)
This leads the app the to start in landscape mode, but if I rotate the device it still changes its orientation. Also, when I have a UIViewController presented with presentationStyle UIPresentationFormSheet it rotates to portrait the moment it shows.
In some other threads / forums it was adviced to create a category for UIViewController and rewrite
-(UIDeviceOrientation)interfaceOrientation;
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
To always rotate to the Device Orientation (LandscapeLeft) or specifically LandscapeLeft, also to no AutoRotate unless you rotate to LandscapeLeft.
When I set these functions like this (Or for example allow no rotation at all) the app always appears in portrait mode, and wont rotate, not even to LandscapeLeft. The only way to have the app start in Landscape mode is when I allow for rotation no matter what the interfaceOrientaton is.
Does anybody know how I can fix this?
The category I implemented:
#implementation UIViewController(Extends)
-(UIDeviceOrientation)interfaceOrientation
{
return [[UIDevice currentDevice] orientation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft)
return YES;
else
return NO;
}
#end
The only place that I can find a Portrait Orientation to be defined is the original window on the MainWindow.xib, but this cannot be altered, and every thread/forum says that that particular setting is/should not be the issue.
As far as I can tell the steps you took should prevent rotation of the interface.
You can always try to override the calls that do the orientation in every viewcontroller of your app. That should at least give you a clue where the rotation is happening. After which a breakpoint can possibly tell you more.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
NSLog( #"will rotate to orientation %d in %#", interfaceOrientation, NSStringFromClass([self class])
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
NSLog( #"did rotate from orientation %d to %d in %#", fromInterfaceOrientation, [self interfaceOrientation], NSStringFromClass([self class])
}

Is there a way to force the interface orientation to change in iPhone?

I know how to allow/disallow the orientation to rotate using
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
However, I have the problem now where the phone might be in portrait (or upsidedown) and at some point I want to rotate the screen as if the user rotated to landscape. At this point, I don't want autorotate to work anymore. I want to force the interface orientation to stay in landscape. Is there a way to do this? I can probably figure out a hack for turning off the autorotate, but forcing the rotation in the first place I have no idea how to do.
Here's what I'm trying to do:
The app rotates to any and all orientations. Everything is normal.
An event occurs.
Now the autorotate only works for landscapeleft and landscaperight. Moreover, if the user is in portrait or portraitupsidedown, I programmatically rotate to landscaperight to lock the user into that orientation.
Just to make things trickier, I want to pop up a UIAlertView (I know how to do that) before the forced rotation, letting the user know what's going on, and I want to screen behind the alertView to rotate but not the alertView. Is this even possible?
Thanks.
The best solution for your situation is to notify the user to turn it to landscape orientation and pause the program until the user turns the orientation. And then when the user rotates the device you can handle the delegate methods and start displaying the screen in the landscape mode. This approach has been handled in many of the app store applications and looks like it is one of the best ways to get the app approved in app store. I hope it makes sense.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown || interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
// orientation view swapping logic
- (void)didRotate:(NSNotification *)notification {
UIDeviceOrientation newOrientation = [[UIDevice currentDevice] orientation];
if (newOrientation != UIDeviceOrientationUnknown || newOrientation != UIDeviceOrientationFaceUp || newOrientation != UIDeviceOrientationFaceDown)
{
orientation = newOrientation;
}
// Write your orientation logic here
if ((orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight))
{
// Clear the current view and insert the orientation specific view.
[self clearCurrentView];
[self.view insertSubview:yourLandscapeView atIndex:0];
} else if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown)
{
// Clear the current view and insert the orientation specific view.
[self clearCurrentView];
[self.view insertSubview:yourPortraitView atIndex:0];
}
}
and add that notification in the event
You cannot. At least not in a way that Apple will allow. The autorotation is designed to be the same for the whole application. You can make code that rotates the view manually, but as far as UIDevice is concerned you'll be in the same orientation.
According to Apple, if you do not want the default behavior provided by the device orientation rotation API:
You can take control over:
The orientations supported by your app
How a rotation between two orientations is animated on screen.
The way I read this is "You can control either of these things, but nothing else" or "You're allowed to control only these two things."
I do not see anything in the documentation that explicitly tells you how to "force" the orientation to change. All of that is handled by the device so as it seem more natural and friendly to the person holding the device. Does that make sense?
See the docs here on rotation changes:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html
Finally, I would say this is not possible, and further that it would not be approved by Apple. I up voted Praveen's answer because I think you may need to consider a different approach for what you're trying to do.
yes you ca do that. what you have to do is in -(void) viewwillappear method simply include the following code
if (self.interfaceOrientation == <current orientation>) {
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:") withObject:(id)<to which orientation you want to change.>];
}
it will solve your problem

Resources