Rotation broken in iOS6 - iphone

I've been trying all morning to fix this, to no avail. Here's my situation:
I have a navigation controller across two views in my app. The first view shouldn't rotate away from portrait. The second view should rotate between portrait and landscape. Going back to the first view should send it back to portrait.
Here's the code I have currently (which i've experimented with without success, so is in no way solid):
AppDelegate:
- (NSUInteger)application:(UIApplication*)application
supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
return UIInterfaceOrientationMaskAll;
}
Navigation controller:
- (BOOL)shouldAutorotate
{
return self.topViewController.shouldAutorotate;
}
First view controller:
-(BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Second view controller:
-(BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
The current behaviour is that app will stay in portait on the first VC, rotate properly on the second VC, but if I go back while in landscape, the first VC is in landscape and stays there. How can I fix this?

I was having the same issue, and as far as I can remember, you can't fix it due to the way how auto-rotation works. However, I did come up with a workaround - when in landscape mode, I hid the navigation bar, disabling the option to tap the back button. This might or might not work for you, but if you come up with a better solution, I would love to hear it.

Related

iOS7 / iOS6 Conditional Rotation Portrait / Landscape for different sections of App

Problem: A have an App that uses both Landscape mode (locked) and Portrait Mode (locked) for different parts of the app. Now I have a working solution however it doesn't seem correct and does have it's own problems.
Optimally I would love to force a orientation change. Thinking even about doing a view transformation if needed.
Basic flow of App:
HomeView (Portrait) (which has a few sub pushed views that are also portrait and locked to that).
LandscapeView (Landscape) (which has 5 pushed subviews that are also landscape)
Note:
HomeView has a link to LandscapeView
LandscapeView can go back to HomeView
At the end of the LandscapeView subviews it returns to the HomeView
Basic Image showing how this looks with the different view orientations. (The lines indicate flow of app, orientation of the images indicate how each screen should be )
Currently using the below implementation to call / set if the view is in portrait mode or landscape mode by [setLockedToPortait:YES] (for portrait view) etc.
This in term makes the query for what interface orientation to use from iOS if the device is rotated.
Now for the case of going to the LandscapeView, I show a temporary view over the top of the normal view asking to use to rotate their phone to landscape. (A temporary view is also shown when returning to the HomeView from a landscape view)
So once the user has rotated their device, it will trigger the correct orientation and then the temporary view will hide.
If the user then rotates their phone back to portrait at this point it will still be locked to landscape so will not trigger another view rotation (also no temp view will appear or anything)
Current Implementation Code::
// ---------------------- NavigationController (subclass of UINavigationController)
#interface NavigationController () {
BOOL isOrientationPortrait;
}
#end
#implementation NavigationController {
UIDeviceOrientation lastAccepted;
UIDeviceOrientation lastKnown;
}
-(void)setLockedToPortait:(BOOL)isLocked {
isOrientationPortrait = isLocked;
}
-(UIDeviceOrientation) getCurrentOrientation {
UIDeviceOrientation orientate = [[UIDevice currentDevice] orientation];
if(orientate == 0) { // needed for simulator
orientate = (UIDeviceOrientation)[UIApplication sharedApplication].statusBarOrientation;
}
return orientate;
}
// Deprecated in iOS6, still needed for iOS5 support.
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
{
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastKnownOrientation:orientation];
if(isOrientationPortrait == YES) {
if([self isLastKnownPortrait] == YES) {
[self setLastAcceptedOrientation:orientation];
return YES;
} else {
return NO;
}
} else {
if([self isLastKnownLandscape] == YES) {
[self setLastAcceptedOrientation:orientation];
return YES;
} else {
return NO;
}
}
}
// iOS6/7 support
- (BOOL)shouldAutorotate
{
// find out the current device orientation
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastKnownOrientation:orientation];
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if(isOrientationPortrait == YES) {
if([self isLastKnownPortrait] == YES)
{
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastAcceptedOrientation:orientation];
}
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown);
} else {
if([self isLastKnownLandscape] == YES)
{
UIDeviceOrientation orientation = [self getCurrentOrientation];
[self setLastAcceptedOrientation:orientation];
}
return (UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight );
}
}
-(void)setLastAcceptedOrientation:(UIDeviceOrientation)orient {
lastAccepted = orient;
}
-(void)setLastKnownOrientation:(UIDeviceOrientation)orient {
lastKnown = orient;
}
-(BOOL)isLastKnownPortrait {
return UIDeviceOrientationIsPortrait(lastKnown);
}
-(BOOL)isLastKnownLandscape {
return UIDeviceOrientationIsLandscape(lastKnown);
}
-(BOOL)isLastAcceptedPortrait {
return UIDeviceOrientationIsPortrait(lastAccepted);
}
-(BOOL)isLastAcceptedLandscape {
return UIDeviceOrientationIsLandscape(lastAccepted);
}
Current Problems:
Device rotations are always required after a view has loaded for the user going to Landscape mode from Portrait and vice versa.
If the user has the device orientation locked, this will not work at all.
When transitioning back from Landscape mode, and the user has already rotated their device to Portrait (in the last landscape view), the Portrait view's interface will be locked to a 'Landscape' layout until the user re-rotates their device (so currently I am just showing the overlay to rotate the device, but it is already rotated… very annoying for the user). Massive issue right now with the above implementation.
Would love to be able to:
Force an orientation change on the phone for the current view.
Set a preferred layout for a view which is forced between push/pops of views.
I've looked a lot at the other solutions on here and on the Apple Dev forums, however none seem to cover this problem, or still this orientation bug between the two views exists as well.
Thanks for any help or pointers! No advice will be discounted :D
--
Edit::
Solution Found thanks to #leo-natan!!
So instead of trying to force a change of orientation on the views. Just push a new modal view. This forces a change. You still need to above orientation code for managing rotations.
So what I have now in my HomeViewController:
LandscapeViewController * viewController = [[[LandscapeViewController ViewController alloc] init] autorelease];
UINib * nib = [UINib nibWithNibName:#"NavigationController" bundle:nil];
NavigationController *navController = [[nib instantiateWithOwner:nil options:nil] objectAtIndex:0];
[navController initWithRootViewController:viewController];
[self presentViewController:navController animated:YES completion:^{
// completion
}];
So it is necessary to re-add a new navigation controller for this modal view. Also note above 'presentViewController' is the new way of pushing Modal views.
Implemented this overloaded method for the managing of the view controller:
-(id)initWithRootViewController:(UIViewController *)rootViewController {
self = [super initWithRootViewController:rootViewController];
if(self){
}
return self;
}
Note: The above is not using storyboards. The problem may be solved by using storyboards and modally showing a view in the same fashion.
See my answer here, including a test project.
Basically, orientation can only be forced to change when presenting a view controller modally. For example, media playback in some apps. If you wish to transition from a view controller that can only be presented in portrait to a view controller that is only presented in landscape, you will need a modal presentation. Push will not work.

how can i turn keyboard in iOS6.0?

i have a portrait view (status bar hidden), but i turned it. Then keyboard shows this:
i want keyboard to turn and fullscreen. Please help me. Thanks in advance.
I have seen the comments.
You can't make the screen be landscape like this. IOS 6 has something new, "the app's appDelegate always start as portrait"
You should use the IOS 6 autorotate!
This should be in the appDelegate:
- (NSUInteger)application:(UIApplication*)application
supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
return (UIInterfaceOrientationMaskAll);
}
In your view controller:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
in the supportedInterfaceOrientations you can set it to landscape only

Making a view go portrait straight away without rotating

Currently i have this code in all my views which i don't want to go into landscape which is all except for one:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// You do not need this method if you are not supporting earlier iOS Versions
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
-(NSUInteger)supportedInterfaceOrientations
{
if (self.selectedViewController)
return [self.selectedViewController supportedInterfaceOrientations];
return UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotate
{
return YES;
}
this is the code in my tab bar controller:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// You do not need this method if you are not supporting earlier iOS Versions
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
-(NSUInteger)supportedInterfaceOrientations
{
if (self.selectedViewController)
return [self.selectedViewController supportedInterfaceOrientations];
return UIInterfaceOrientationMaskPortrait;
}
-(BOOL)shouldAutorotate
{
return YES;
}
And lastly the code in the viewcontroller that i want to go into landscape (because there is a video):
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
The views are all rotating like i want them to, the only problem is when the viewcontroller with the video in rotates and you then click on another view that view will stay in landscape, what i want to happen is this view to rotate straight into portrait without the user rotating the device into portrait. Anyone know what code i need?
This can be a difficult one to solve elegantly. Forcing orientation can be breaking Human Interface Rules rules or in the past just required calling private API's
I would recommend attempting a different approach which has worked for me in the past. When the user rotates the one viewcontroller that displays a video allow that to rotate but at that time remove any way the user can navigate away and then return those navigation controls when they rotate the device back to portrait. For me it was simply hiding the navigation bar until they returned to portrait. I like this because it is very clear to the user that they have to return the phone to portrait before moving on and they won't be surprised with navigating somewhere else that is magically another orientation.

iPhone landscape issues

xcode:4.5.2
I want to create an application in iPad;
I settings my info.plist as below:
Initial interface orientation: Landscape (left home button)
When I started my app, the orientation device have landscape mode, but my view not rotate to this orienatation.
I don't know what it is, who can help me
are you implements these following methods.
-(BOOL)shouldAutomaticallyForwardAppearanceMethods{
// This method is called to determine whether to
// automatically forward appearance-related containment
// callbacks to child view controllers.
return YES;
}
-(BOOL)shouldAutomaticallyForwardRotationMethods{
// This method is called to determine whether to
// automatically forward rotation-related containment
// callbacks to child view controllers.
return YES;
}
In ios6 you have to use this method for vieworientation
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationMaskAll;
}

auto-rotation in iOS5/6?

I updated to Xcode 4.5 and am working with iOS6--a mistake I will definitely not make next time there's an update; it's been sort of nightmarish for somebody so new to iOS--and I've just noticed an app I'm working on is autorotating. I never noticed it autorotatin before the update, but it's also possible I just didn't rotate the phone while testing, so I can't be sure. I've added the following code to the main UIViewController and it's still rotating:
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
return NO;
}
Is this the right way to disable autorotation? If it is, then maybe there's some change in iOS6 and I'll have to wait until the full release to find out. But if I've gotten it wrong, what code should I use instead?
Thanks, as always, for your help.
EDIT: Here's the code I changed it to, but it's still rotating. Have I gotten it wrong?
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
return YES;
}
else
{
return NO;
}
}
that is because there was never a success. You should choose one of the orientations.
Hold command and click on UIInterfaceOrientation you will see an enumeration of the possible options.
then you can test against those to decide your YES Scenario.
I may have originally misunderstood your problem. It seems that you may have been saying that your app is allowing rotation. but the code should disallow that.
I was thinking you were saying it was still firing the code. Trying to find a Yes
One thing to think about. is there may be more than one view controller available. perhaps your code is not being hit.
A couple of possible issues for this.
Your code is not even being used. because the view is being allocated as UIViewController as opposed to your custom view controller.
You code is being used but that View controller is not the one being asked about the Orientation. therefore that specific code is not being hit.
A bad build keeps putting the wrong assemblies onto the device.
Your solutions can be as follows.
Ensure your code is the one being allocated. Either there is a direct alloc on your custom class. or the xib file is inflating it. Check out the Identity Inspector when you have your xib file open. select your View Controller and ensure that custom class is set to your class type
Look at the hierarchy. what other view controllers are there. Perhaps one of those are telling the app it can autorotate to any orientation.
Find your "DerivedData" folder and remove it entirely. Sometimes this works from the organizer. other times you need to delete directly off the disk. Then clean and build again.
Also another solution could be as simple as setting the settings in the Project file.
Select your project file from the file browser and you will see the iPad and iPod settings in the summary. You can "UnPress" buttons for the orientations that you want to disallow. and any view controllers that you do not otherwise code orientation into. will use these by default.
My apologies for the confusion.
Update
I commonly use this code to handle my autorotation.
It not only differentiates the ipad from the other ios devices, but it also forwards the request onto presented controllers so a view that is shown modal may respond how it wants.
Orientation is a pain when you dont understand it :)
// Detect iPad
#define IS_IPAD() ([[UIDevice currentDevice] respondsToSelector:#selector(userInterfaceIdiom)] ? \
[[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad : NO)
// Set preferred orientation for initial display
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
if (IS_IPAD()){
return UIInterfaceOrientationLandscapeRight;
}
else {
return UIInterfaceOrientationPortrait;
}
}
// Return list of supported orientations.
- (NSUInteger)supportedInterfaceOrientations{
if (self.presentedViewController != nil){
return [self.presentedViewController supportedInterfaceOrientations];
}
else {
if (IS_IPAD()){
return UIInterfaceOrientationMaskLandscapeRight;
}
else {
return UIInterfaceOrientationMaskAll;
}
}
}
// Determine iOS 6 Autorotation.
- (BOOL)shouldAutorotate{
UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;
// Return yes to allow the device to load initially.
if (orientation == UIDeviceOrientationUnknown) return YES;
// Pass iOS 6 Request for orientation on to iOS 5 code. (backwards compatible)
BOOL result = [self shouldAutorotateToInterfaceOrientation:orientation];
return result;
}
// handle iOS 5 Orientation as normal
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
// Return YES for supported orientations
if (self.presentedViewController != nil){
return [self.presentedViewController shouldAutorotate];
}
else {
if (IS_IPAD()){
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
else {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
}
}
Rotation APIs have changed in iOS6. The new API's are apparently supposed to be opt in however they seem to be enabled for all debug builds on simulator or device. To register for the new API calls throw something like this in your APP Delegates didFinishLoading method.
//Register for new API rotation calls
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"UIApplicationSupportedInterfaceOrientationsIsEnabled"];
At the heart of the rotation changes are two methods (theres a third but Im still figuring this out myself)
- (BOOL)shouldAutorotate
- (NSUInteger)supportedInterfaceOrientations
You need to override these methods in your windows rootViewController. This means you need to subclass UINavigationController or UITabBarController if either is your root controller (this seems bizarre to me, but Apple says Jump).
Now if all you want to do is keep your app in portrait implement the two methods and you're golden.
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Note that apple has further added to the confusion by adding interface orientation masks, ie. UIInterfaceOrientationMaskPortrait != UIInterfaceOrientationPortrait. If you return UIInterfaceOrientationPortrait instead the behaviour will be different. Also you can combine masks the same way you combine orientations so if you wanted to support both portrait orientations you could use.
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
}
That should work for forcing a portrait orientation. Now if you if you want do do something like allow a child controller to use a different orientation I have no clue.
A very simple way to handle autorotation in both iOS6 and iOS5 is to use supportedInterfaceOrientations & shouldAutorotateToInterfaceOrientation. There are some macros to make it just a line of code. UIInterfaceOrientationIsLandscape & UIInterfaceOrientationMaskLandscape.
I discovered UIInterfaceOrientationMaskLandscape & UIInterfaceOrientationMaskPortrait by auto-completion in xCode. It is not in the Apple docs about autorotation.
Add this code block to your root ViewController to force it to support only landscape mode.
//iOS6 code to support orientations
- (NSUInteger)supportedInterfaceOrientations
{
return (UIInterfaceOrientationMaskLandscape);
}
//iOS5 code to support orientations
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
return (UIInterfaceOrientationIsLandscape(orientation));
}
For iOS6 you can use the following to detect orientation:
UIInterfaceOrientationMaskLandscape
UIInterfaceOrientationMaskPortrait
UIInterfaceOrientationMaskLandscapeRight
UIInterfaceOrientationMaskLandscapeLeft
UIInterfaceOrientationMaskPortraitUpsideDown
UIInterfaceOrientationMaskAllButUpsideDown
UIInterfaceOrientationMaskAll
For iOS5 and below you can use the following to detect orientation:
UIInterfaceOrientationIsLandscape (A macro)
UIInterfaceOrientationIsPortrait
UIInterfaceOrientationIsLandscapeRight
UIInterfaceOrientationIsLandscapeLeft
UIInterfaceOrientationIsPortraitUpsideDown