UITabBarController Rotation Issues in ios 6 - objective-c

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!

Related

ObjC disable ViewController rotation

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;
}

shouldAutorotateToInterfaceOrientation is not being called

Hi i am now problem with orientation of viewcontroller. the following is my .h file.
#interface IPad_HomeViewController : UIViewController <UINavigationControllerDelegate>{
UIAlertView *alertWithYesNoButtons;
}
#property (weak, nonatomic) IBOutlet UILabel *lblStatus;
#end
i implement the following method in .m file.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return NO;
}
then i made a breakpoint. i realized shouldAutorotateToInterfaceOrientation is totally not being called. don't know why it is not being called.
pls advise me.
thanks
I think it is because your UINavigationController handles the call. Implement the following to send it back to the viewController.
- (BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
// pre-iOS 6 support
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
Rotation support changed a lot between iOS 5 and iOS 6.
Go to your project's target summary page and check "iPhone/Ipod Deployment Info" and there "Supported Interface Orientations". Have you enabled device rotation?

ios 6 App is rotating, even with shouldAutorotate:NO

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;
}

Handling Rotation in iOS6

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...

How do I make rotation work properly in iOS 6 GM in a tab bar app?

Rotation was working JUST FINE with iOS 5 and now it doesn't work at all. I had it set so that ALL of my views stayed Portrait exception when on Tab 1 when a certain view was open, then users could rotate and it would show a coverflow-style view.
My setup is that I create my tabbar at runtime in the AppDelegate. I then set it as the main root view:
self.window.rootViewController = self.tabBarController;
But ALL of my views, on all tabs, now rotate left or right no matter what. And I've tried adding the new code (from multiple examples in the forums) to no avail.... I breakpoint everything and NO rotation code ever gets called when I rotate my phone.
Each TabController has within it a NavigationController and then within that has my main views with all of my UI.
Any ideas or pointers on how to do rotation correctly in iOS 6? Very frustrating because this is the final problem I need to fix before I can ship.
This will get you up and running. Ultimately you really should subclass these UIKit classes instead of using categories, but unfortunately that will not work for third party libraries which are not yet fixed for iOS 6. These categories should work for everything without requiring you to muck about in other people's code.
I have yet to see any solution for the UITabBarController or UINavigationController issues that do not involve subclassing (or writing a category). I wish one existed, though.
Make sure you import the three .h files (or one if you choose to add them all to a single file) at the top of your Prefix.pch file. You must make sure this code is loaded ASAP!
UITabBarController+LegacyRotation.h
#import <UIKit/UIKit.h>
#interface UITabBarController (LegacyRotation)
#end
UITabBarController+LegacyRotation.m
#import "UITabBarController+LegacyRotation.h"
#implementation UITabBarController (LegacyRotation)
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
}
#end
UINavigationController+LegacyRotation.h
#import <UIKit/UIKit.h>
#interface UINavigationController (LegacyRotation)
#end
UINavigationController+LegacyRotation.m
#import "UINavigationController+LegacyRotation.h"
#implementation UINavigationController (LegacyRotation)
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
}
#end
UIViewController+LegacyRotation.h
#import <UIKit/UIKit.h>
#interface UIViewController (LegacyRotation)
#end
UIViewController+LegacyRotation.m
#import "UIViewController+LegacyRotation.h"
#implementation UIViewController (LegacyRotation)
- (NSUInteger)supportedInterfaceOrientations
{
NSUInteger ret = 0;
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) {
ret |= UIInterfaceOrientationMaskPortrait;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortraitUpsideDown]) {
ret |= UIInterfaceOrientationMaskPortraitUpsideDown;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeLeft]) {
ret |= UIInterfaceOrientationMaskLandscapeLeft;
}
if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight]) {
ret |= UIInterfaceOrientationMaskLandscapeRight;
}
return ret;
}
- (BOOL)shouldAutorotate
{
return YES;
}
#end
I just needed to add the following method in the appDelegate , in order for the rotation to
work on ios 6.
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:
(UIWindow *)window{
return UIInterfaceOrientationMaskAll;
}
Where as for ios 4 & 5 we still have to use :
(BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation in the specific view controller