I have been trying to do this for 2 weeks, and just found out the reason it's not working:
Deprecated APIs
The following APIs are deprecated:
The UIViewController methods and properties for interface orientation. Traits and size classes replace them, as described in Unified Storyboards for Universal Apps.
From what's new in iOS 8
What I need is: a FirstViewController, which is the rootViewController to my navigationController. The FristViewController should be only available in Portrait mode (not ever ever ever displayed in Landscape).
Then there are a few intermediate ViewControllers in the navigation stack (which support both orientations), until I reach a LastViewController, which should be available only in LandscapeRight mode (and never ever ever in portrait, or another mode).
I have been trying with the following CustomNavigationController, but apparently things changed in iOS8, and I can't get it to work:
- (BOOL)shouldAutorotate { // Available in iOS 6.0 and later
return YES; // // May use topViewController's, but in this app it always returns YES
}
- (NSUInteger)supportedInterfaceOrientations { // Available in iOS 6.0 and later
if (self.topViewController != nil)
return [self.topViewController supportedInterfaceOrientations];
else
return [super supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { // Available in iOS 6.0 and later
if (self.topViewController != nil)
return [self.topViewController preferredInterfaceOrientationForPresentation];
else
return [super preferredInterfaceOrientationForPresentation];
}
Thanks!
The problem you are having has nothing whatever to do with iOS 8. Here are some points to note:
You have misunderstood the note about what's deprecated. Only methods with names like willRotate are deprecated, and you are not using them anyway.
Nothing has changed with regard to how supportedInterfaceOrientations works. Make sure you test with beta 4, though, because there was a bug in betas 1-3 that prevented presented view controller orientations from working correctly.
"Then there are a few intermediate ViewControllers in the navigation stack (which support both orientations), until I reach a LastViewController, which should be available only in LandscapeRight"... That is impossible, but not because of iOS 8. What you are describing has been illegal since iOS 6! You cannot have different forced orientations for different view controllers in a navigation stack. Only a presented view controller can force rotation (as I have explained here and in many other answers: https://stackoverflow.com/a/21616025/341994).
Implement - (NSUInteger)supportedInterfaceOrientations appropriately in each of the view controllers in the navigation stack. It does not matter what the UINavigationController's supported orientations are. It ought to respect the supported orientations of its displayed view controller.
Also make sure that the all the necessary orientations are checked in your target's "General -> Deployment Info" configuration section.
Related
My application is navigation based application which is supporting iOS 6. Except a view controller all others will support only portrait mode. Particular view controller alone has to support both landscape and portrait orientations.
I searched lot there are tons of questions for this but none of the answer is suitable for me. If some one knows, kindly guide me
I set the orientation as Portait in Project -> Targets -> Summary -> Supported orientation
First you should use methods for the iOS6 presented in UIViewController documentation if you are making your app for iOS6. Orientation method like shouldAutorotateToInterfaceOrientation is deprecated in iOS6, alternate method for iOS6 is shouldAutoRotate. You should only use the old method if your app is supporting also iOS5.
Second If you are using UINavigationcontroller in your application and you need to have different interface orientations then navigationController could mess up the interface orientation in the application. Possible solution (worked for me) is to implement a custom UINavigationController and override the interface orientation methods within that custom UINavigationController class, this will make your viewControllers rotate according to the orientation you set because your controllers are pushed from the UINavigationController. Don't forget to add those methods in your particular viewController also.
CustomNavigationController.h
#interface CustomNavigationController : UINavigationController
#end
CustomNavigationController.m
#implementation CustomNavigationController
//overriding shouldRotate method for working in navController
-(BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
I really think that the correct way to do it is to set both landscape and portrait as supported orientations, and not allowing a change in the orientation on the VC you don't want to rotate, by returning NO on the
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
if the orientation that was passed to the method was not supposed to be supported.
As mentioned in the comments, this method can no longer be used. You should use :
-(BOOL) shouldAutorotate
And find out the current orientation inside this function and returning NO if you don't want to rotate.
Don't forget to allow your application different Orientations!
otherwise nothing from above will work
Set it in project target on General under Deployment Info section:
I have a app which i want to display in portrait mode. But I only want to show one view in both modes.
I have do this for iOS5 . But in iOS6,i can't able to do this.
I also tried many codes to solved it.
i use navigation in my app & rotate only one view in both mode is not possible in ios6. Either you fixed your rotation for a view or rotate whole app. Am i right?
How can I solve this problem?
in ios6 have you trying with this in plist like bellow image:-
and you can also set at xcode->projectname->summary:-
From Apple's iOS 6 SDK Release Notes:
Autorotation is changing in iOS 6. In iOS 6, the
shouldAutorotateToInterfaceOrientation: method of UIViewController is
deprecated. In its place, you should use the
supportedInterfaceOrientationsForWindow: and shouldAutorotate methods.
More responsibility is moving to the app and the app delegate. Now, iOS containers (such as UINavigationController) do not consult
their children to determine whether they should autorotate. By
default, an app and a view controller’s supported interface
orientations are set to UIInterfaceOrientationMaskAll for the iPad
idiom and UIInterfaceOrientationMaskAllButUpsideDown for the iPhone
idiom.
A view controller’s supported interface orientations can change over time—even an app’s supported interface orientations can change
over time. The system asks the top-most full-screen view controller
(typically the root view controller) for its supported interface
orientations whenever the device rotates or whenever a view controller
is presented with the full-screen modal presentation style. Moreover,
the supported orientations are retrieved only if this view controller
returns YES from its shouldAutorotate method. The system intersects
the view controller’s supported orientations with the app’s supported
orientations (as determined by the Info.plist file or the app
delegate’s application:supportedInterfaceOrientationsForWindow:
method) to determine whether to rotate.
The system determines whether an orientation is supported by intersecting the value returned by the app’s
supportedInterfaceOrientationsForWindow: method with the value
returned by the supportedInterfaceOrientations method of the top-most
full-screen controller. The setStatusBarOrientation:animated: method
is not deprecated outright. It now works only if the
supportedInterfaceOrientations method of the top-most full-screen view
controller returns 0. This makes the caller responsible for ensuring
that the status bar orientation is consistent.
For compatibility, view controllers that still implement the shouldAutorotateToInterfaceOrientation: method do not get the new
autorotation behaviors. (In other words, they do not fall back to
using the app, app delegate, or Info.plist file to determine the
supported orientations.) Instead, the
shouldAutorotateToInterfaceOrientation: method is used to synthesize
the information that would be returned by the
supportedInterfaceOrientations method.
If you want your whole app to rotate then you should set your
Info.plist to support all orientations. Now if you want a specific
view to be portrait only you will have to do some sort of subclass and
override the autorotation methods to return portrait only.
See this example How to force a UIViewController to Portrait orientation in iOS 6
EDIT:
Solutions:
#implementation UINavigationController (Rotation_IOS6)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
#end
THIS IS NOT A DUPLICATE QUESTION. A final working solution has NOT been provided yet so please do not close this question until we've accepted an answer or found and provided our own 100% working solution. Thanks!
==================================================================
Using Xcode 4.5.1, we have a tab-bar app with 5 tabs in it. Each tab contains a UINavigationController, so the entire App thus needs to be viewed in Portrait mode. There is one exception: an "image-gallery" type view controller that we need to open and be viewed full-screen, and in LANDSCAPE mode.
We were able to do this easily in iOS5 using the following code in that one particular ViewController:
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
But shouldAutorotateToInterfaceOrientation has been deprecated in iOS6 and doesn't work any more.
So, to get this to work in iOS6, we've taken the following steps so far:
1) created a subclass of the UITabBarController (which is our rootViewController)
2) set its supportedInterfaceOrientations and preferredInterfaceOrientationForPresentation to UIInterfaceOrientationMaskPortrait (But note that we are NOT implementing the shouldAutorotate method in it)
3) Set the PROJECT/Target supported orientations to ALL
This ALMOST works perfectly: our "Image Gallery" ViewController does respond to both landscape modes - as it should - but it still initially opens in Portrait - which is bad. We need it to open up right in Landscape - and not ever be able to be displayed in Portrait. Right now it still doing both.
Any idea why its doing that - or how to fix it?
I had this exact same problem with an app I work on and this is how I solved it.
First I created a subclass of UITabBarController called NonRotatingTabBarController with the portrait orientation code
NonRotatingTabBarController.h
#import <UIKit/UIKit.h>
#interface NonRotatingTabBarController : UITabBarController
#end
NonRotatingTabBarController.m
#import "NonRotatingTabBarController.h"
#implementation NonRotatingTabBarController
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
#end
Now when you create your Tab Bar Controller, it needs to be an instance of NonRotatingTabBarController
self.tabBarController = [[NonRotatingTabBarController alloc] init]; // or whatever initialising code you have but make sure it's of type NonRotatingTabBarController
Now in the ONLY view controller which needs to have landscape support, you need to override the rotation methods so it does rotate. In my case, it had to be fixed to landscape
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return (UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
In your project/target settings, you MUST have support enabled for all the interface orientations your app uses otherwise it will crash. Let the code above take care of rotation enabling/disabling.
Hope that helps!
shouldAutorotateToInterfaceOrientation method is deprecated in iOS 6
try to implements these following methods.
-(BOOL)shouldAutomaticallyForwardAppearanceMethods{
// This method is called to determine whether to
// automatically forward appearance-related containment
// callbacks to child view controllers.
}
-(BOOL)shouldAutomaticallyForwardRotationMethods{
// This method is called to determine whether to
// automatically forward rotation-related containment
// callbacks to child view controllers.
}
note : these methods just supported in iOS 6.
I have a viewcontroller in which I wanted it to be presented only in portrait, so I did the following in iOS 6:
-(BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
however when I rotate the device, it still turns it to landscape. Any idea where else to check this? I put a break point and it hits supportedInterfaceOrientations, but it still rotates
Do you have a navigation controller? The way that iOS6 determines what can be autorotated has changed. It is correctly asking supportedInterfaceOrientations for your view controller but it is probably asking "shouldAutorotate" to another element in your navigation stack hierarchy and accepting that answer. If your navigationController/tabviewController returns yes to this question then it won't consult with your view controller.
You should also provide the apps supported orientations in the app delegate:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
return UIInterfaceOrientationMaskPortrait;
}
Make sure you add the root view controller properly (not adding it as a subview), but using the following:
[window setRootViewController:myVC];
Also if your view controller is inside a UINavigationController, you should use this category for the navigationcontroller:
#implementation UINavigationController (autorotate)
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
#end
In iOS 6, only the root view controller of the top most full screen controller is asked about rotation. This includes UINavigationController, this class does not ask it's view controllers, it responds directly. Apple now suggest subclassing UINavigationController to override supportedInterfaceOrientations's output.
Make sure that your project settings and info.plist have only portrait orientation selected as they have a higher priority than the app delegate when checking for supported orientations
I am updating my app for iOS 6 and having issues with the changes to autorotation. My app has a bunch of view controllers and all of them should only support the portrait layout except 1 which should support all 3 orientations except upside down.
If I add the application:supportedInterfaceOrientationsForWindow: method to the app delegate do I have to add conditions there to check if im displaying the one VC I want to be able to rotate?
The documentation states that if I implement supportedInterfaceOrientations on a VC it should override the app delegate method but this doesn't appear to be the case. I have an log statement in the method on the child VC and it is called once when the VC loads but its not called when I rotate the device, but the method in the app delegate is.
If I completely remove the method from the app delegate the orientation of my VC's seems to be completely dependent on my apps supported interface orientation settings. This of course seems to be due to the method supportedInterfaceOrientations being called once on creation of the VC but never when the device is rotated.
Does anyone have any ideas or suggestions? It would be much appreciated.
Replace
[window addSubview:viewController.view];
with
window.rootViewController = viewController;
You also need to override - (BOOL) shouldAutorotate and return "YES". This makes it so you declare what orientations your VC supports with "supportedInterfaceOrientations" and then on rotation it should call "shouldAutorotate". If you have any navigation controller or tabbar you may need to subclass those to do the same thing within them. I had this issue recently myself.
try this...
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
{
// here to implement landscope code
}
else
{
// here to implement setframePortrait
}
}