I only want to support different Orientations on one View in my UINavigationController Stack. How can I do this?
It also has to work in iOS5.
I've had a lot of trouble with how iOS6 handles Orientation, hopefully this is what you're looking for.
Create a category of UINavigationController and call it "UINavigationController+autoRotate".
Put this in your UINavigationController+autoRotate.h:
#import <UIKit/UIKit.h>
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation;
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
Put this in UINavigationController+autoRotate.m:
#import "UINavigationController+autoRotate.h"
#implementation UINavigationController (autoRotate)
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [self.topViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
- (BOOL)shouldAutorotate
{
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations
{
if (![[self.viewControllers lastObject] isKindOfClass:NSClassFromString(#"ViewController")])
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
else
{
return [self.topViewController supportedInterfaceOrientations];
}
}
#end
For Views that you DO NOT want to rotate, add:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
And for Views you DO want to rotate:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIDeviceOrientationPortraitUpsideDown);
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
- (BOOL)shouldAutorotate
{
return YES;
}
In your App's delegate, add:
- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
I recommend you to NOT create a category on UINavigationController to override those methods. Categories are not aimed to do that, and there is no warranty that your code is going to be loaded instead of Apple's one (even if actually that works). I advise you to create a subclass of UINavigationController, and override those methods in it.
The solution does not work on iOS 6 (ok on iOS 5) when:
vc A is supporting only portrait orientation
vc B is supporting all orientations
we push vc B from vc A, rotate vc B (e.g. in landscape) and pop back to vc A. vc A orientation stays in landscape mode...
Related
I'm trying to disable screen rotation in just one ViewController. I'm using this to change screen orientation to portrait:
-(void)viewDidAppear:(BOOL)animated{
NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
[[UIDevice currentDevice] setValue:value forKey:#"orientation"];
}
and I'm disabling rotation like this:
- (BOOL)shouldAutorotate{
return NO;
}
- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
-(NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController *)navigationController {
return navigationController.topViewController.supportedInterfaceOrientations;
}
but it's not working. It rotates screen to portrait but it does't lock it, if I turn device it changes screen orientation.
You can try this code:
-(BOOL)shouldAutorotate
{
return NO;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
The above code will only work with UIViewControllers not UINavigationController stacks. If you are using a UINavigationController you should do the following:
Solution 1:
Add to AppDelegate.h a variable: #property (nonatomic , assign) bool blockRotation;
Add to AppDelegate.m function:
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (self.blockRotation) {
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAll;
}
In controller want disable add this code:
#import "AppDelegate.h"
//Put to `viewDidload`
AppDelegate* shared=[UIApplication sharedApplication].delegate;
shared.blockRotation=YES;
Solution 2: you can follow this answer: Hanling orientation
If you want to temporarily disable automatic rotation, avoid manipulating the orientation masks to do this. Instead, override the shouldAutorotate method on the initial view controller. This method is called before performing any autorotation. If it returns NO, then the rotation is suppressed.
So you need to subclass 'UINavigationController', implement shouldAutorotate and use your navigation controller class in your storyboard.
- (BOOL)shouldAutorotate
{
id currentViewController = self.topViewController;
if ([currentViewController isKindOfClass:[DetailViewController class]])
return NO;
return YES;
}
I have certain viewControllers which are managed by a UINavigationController (push and pop). I want to restrict different viewControllers to different orientations like the first one should be only in Portrait, second in portrait, third in landscape and fourth can be portrait and landscape both. I set a ViewController on isInitialViewController from storyBoard, the
- (BOOL) shouldAutorotate{
return NO;
}
worked without any problem but when i set the navigation controller (managing these four views by push and pop) as isInitialViewController from storyBoard, this function stopped being called and now autoratates. How can I stop autorotating these views using this UINavigationController as the isInitialViewController. I use the following functions depends on which ViewController it is
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIDeviceOrientationPortrait);//choose portrait or landscape}
- (BOOL) shouldAutorotate{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
//return UIInterfaceOrientationMaskLandscape;
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
// return UIInterfaceOrientationLandscapeLeft |
// UIInterfaceOrientationLandscapeRight;
return UIInterfaceOrientationPortrait;
}
Just subclass UINavigationController and override appropriate methods:
.h File:
#interface CustomUINavigationController : UINavigationController
#property BOOL canRotate;
#end
.m File:
#implementation CustomUINavigationController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return self.canRotate;
}
#end
What if you make Objective C category for UINavigation Controller and Override interface orientation methods...I think u try to control the Autorotation.
Objective C category
http://rypress.com/tutorials/objective-c/categories
since iOS6 i have big problems with the rotation. I implemented all the new
rotation methods (shouldAutorotate, preferredInterfaceOrientationForPresentation, supportedInterfaceOrientation), but all views are still rotating. The funny thing is
that the views are keeping their sizes and the rest of the Window (in Landscape) is black.
Thats the way i implement it, is there anything wrong?
#pragma mark -
#pragma mark - InterfaceOrientation iOS 5
//Deprecated in iOS 6
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark -
#pragma mark - InterfaceOrientation iOS 6
- (BOOL)shouldAutorotate{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortraitUpsideDown;
}
Thanks for your help folks.
I solved the Problem by making a category for the navigationcontroller:
#implementation UINavigationController (iOS6fix)
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
#end
Thanks to everyone for the answers!
I had that too, it rotate even if I turnes it to NO.
Two options:
go to your Project settings and change the possible orientations
Remove all the methods for AUTOROTATE. Even if they are set to NO, they rotate for me.
I used the following category on UIViewController to have landscape only on iOS5 and 6. Maybe it helps someone.
#import <UIKit/UIKit.h>
#implementation UIViewController (iOS6fix)
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
#end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Make sure your window to assgin the view controller object to rootViewController, Please don't add controller view as a sub view on window.
self.window.rootViewController = viewController;
}
I am using iOS 6.0 beta and my rotations do not work anymore.
Where can I set a UINavigationControllers supportedOrientations?
According to this http://news.yahoo.com/apple-ios-6-beta-3-changes-182849903.html
a UINavigation Controller does not consult their children to determine whether they should autorotate.
I am not using shouldAutorotateToInterfaceOrientation: anymore as it is deprecated.
Instead I am using supportedInterfaceOrientations: and shouldAutoRotate: and they are working fine until I place a ViewController into a NavigationController (as a Child).
From then on the orientations specified in the ViewController do not work anymore.
It seems it is using the orientations set by the navigation controller (UIInterfaceOrientationMaskAllButUpsideDown)
How can I set the InterfaceOrientations for the NavigationController so that my ViewControllers are locked to Portrait-Orientation?
Do I have to subclass UINavigationController and set the InterfaceOrientations there? Isn't it bad practise to subclass UINavigationController still in iOS 6.0?
Thanks for you help heaps!
Cheers!
If you want it to consult it's children again you can add a category to UINavigationController
#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
Subclass UINavigationController
//OnlyPortraitNavigationController.h
#interface OnlyPortraitNavigationController : UINavigationController
//OnlyPortraitNavigationController.m
#implementation OnlyPortraitNavigationController
- (BOOL)shouldAutorotate {
return NO;
}
-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait; //for locked only Portrait
}
present new subclass navigationController with your portrait ViewController
SomeViewController *onlyPortraitVC = [[SomeViewController alloc]init];
OnlyPortraitNavigationController *portraitNav = [[OnlyPortraitNavigationController alloc]initWithRootViewController:onlyPortraitViewController];
[self presentViewController:portraitNav animated:YES completion:NULL];
this is work on my app hope it can help you.
Ack! I had my tabbar rotation issues resolved finally in iOS 5, but iOS 6 and xcode seem to have broken things... here is what I have:
Target App Summary includes: Supported Interface Orientations - Portraint, Landscape Left, Landscape Right
Every Single View in the App has the following methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return ((interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown) &&
(interfaceOrientation != UIInterfaceOrientationLandscapeLeft) &&
(interfaceOrientation != UIInterfaceOrientationLandscapeRight));
} else {
return YES;
}
}
- (BOOL)shouldAutorotate
{
NSLog(#"am I called1?");
return NO;
}
-(NSUInteger)supportedInterfaceOrientations{
NSLog(#"am I called?");
return UIInterfaceOrientationMaskPortrait;
}
In the views that are not part of the tab bar, rotation is blocked. In ALL the views of the tabbar (there are 5) the app never calls ShouldAutorotate and so rotates. It does seem supportedInterfaceOrientations gets called once when a view loads, but not when it appears if I switch between views, because I get the NSLog, but it seems to ignore the MaskPortrait setting.
I have to leave the landscape enabled in the target because I have a single video player view that needs to rotate (and it does so, fine)
Is this a tabbar bug in iOS 6? Do I need to disable the rotation of the views differently? The shouldautorotatetointerfaceorientation worked great in ios 5
I've been at it for a while
Thanks,
Zack
Zack, I ran into this same issue. It's because you have your viewController embedded inside of a TabBar Controller or UINavigationController and the calls to these methods are happening inside those instead of your normal View (Changed in iOS6).
I ran into this issue because I was presenting a viewController embedded inside a UINavigationController on all my modal views that had Navigation to different views (Signup Process, Login, etc).
My simple fix was to create a CATEGORY for UINavigationController that includes these two methods. I have shouldAutorotate returning NO anyway because I don't want my modal views rotating. Your fix may be this simple, give it a try. Hope it helps.
I created a category and named it autoRotate and selected theUINavigationController option. The M+H file are below.
#import "UINavigationController+autoRotate.h"
#implementation UINavigationController (autoRotate)
-(BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
#end
... and the category .h:
#import <UIKit/UIKit.h>
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
If you have a tab bar like I did, the only thing you need to do is to add the following to your delegate .m file,
#import "AppDelegate.h"
//UITabBarController category to set the view rotations for ios 6
#implementation UITabBarController (Background)
-(BOOL)shouldAutorotate
{
//I don't want to support auto rotate, but you can return any value you want here
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
//I want to only support portrait mode
return UIInterfaceOrientationMaskPortrait;
}
#end
/////here starts the implementation of the app delegate which is gonna be whatever you currently have on your .m delegate
#implementation AppDelegate
// delegate methods and other stuff
#end
I also had the issue that I needed some views to rotate and others not with several Navigation Controllers. I did this by telling the NavigationController to look in the view controller. Here is what I did.
I create a UINavigationController class called RootNavigationController and designated that class as the Custom Class for the Navigation Controllers in storyboard. In the RootNavigationController.m I added the following methods;
- (BOOL)shouldAutorotate {
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.visibleViewController supportedInterfaceOrientations];
}
In each view controller .m file I also added the following methods.
- (BOOL)shouldAutorotate {
//return yes or no
}
- (NSUInteger)supportedInterfaceOrientations{
//return supported orientation masks
}
Doing this allows me to set orientation for each view in its view controller.
Worked for me anyway…
My situation is:
UITabBarController has 2 items: 2 Navigation controller
UINavigationController1 withRootView: ViewController1
UINavigationController2 withRootView: ViewController2.
Now i want ViewController1 set shouldAutorotate:NO/maskPortrait and
ViewController2 set shouldAutorotate/MaskAll.
So my implement: Create UITabBarController category and UINavigationCntroller category like
UITabBarController+autoRotate.h
#interface UITabBarController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
UITabBarController+autoRotate.m
#import "UITabBarController+autoRotate.h"
#implementation UITabBarController (autoRotate)
- (BOOL)shouldAutorotate {
return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
#end
UINavigationController+autoRotate.h
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
UINavigationController+autoRotate.m
#implementation UINavigationController (autoRotate)
- (BOOL)shouldAutorotate {
return [self.visibleViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.visibleViewController supportedInterfaceOrientations];
}
#end
UIViewController1.m
- (BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;;
}
UIViewController2.m
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
It worked like a charm!
In my case, I had a navigation controller embedded within a UITabBarController, and what worked was creating a category like Kunani defined, but extendind UITabBarController instead of UINavigationController. It worked like a charm :)
#import "UINavigationController+autoRotate.h"
#implementation UINavigationController (autoRotate)
-(BOOL)shouldAutorotate {
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
#end
And .h file:
#import <UIKit/UIKit.h>
#interface UINavigationController (autoRotate)
-(BOOL)shouldAutorotate;
- (NSUInteger)supportedInterfaceOrientations;
#end
This will do it in Swift
extension UITabBarController {
public override func shouldAutorotate() -> Bool {
if let selected = self.selectedViewController {
return selected.shouldAutorotate()
} else {
return false
}
}
public override func supportedInterfaceOrientations() -> Int {
if let selected = self.selectedViewController {
return selected.supportedInterfaceOrientations()
} else {
return Int(UIInterfaceOrientationMask.Portrait.rawValue)
}
}
}
extension UINavigationController {
public override func shouldAutorotate() -> Bool {
return self.visibleViewController.shouldAutorotate()
}
public override func supportedInterfaceOrientations() -> Int {
return self.visibleViewController.supportedInterfaceOrientations()
}
}
https://stackoverflow.com/a/30632505/2298002
there are a lot of ambiguous or unforeseen results when handling this situation, especially when it comes to maintaining the orientation for only a specific view controller and not effecting the rest of the app. this algorithm seems to hand all for me
https://stackoverflow.com/a/30632505/2298002
You should add this thing in the UIViewController1.m to make sure that the previous orientation status is reconstructed:
(void)viewDidAppear:(BOOL)animated
{
[[UIDevice currentDevice] performSelector:NSSelectorFromString(#"setOrientation:")
withObject:(id)UIInterfaceOrientationPortrait];
}
Perfect!