28

I have UITabBarController app which plays video and shows other information in other UITabBar tabs. In iOS 6 UIView rotation methods have been deprecated, and now I need to use shouldAutoRotate and supportedInterfaceOrientations methods. For video playing I use MPMoviePlayerViewController.

How to rotate only this player view? I can only rotate whole app, but don't want to do this. I present MPMoviePlayerViewController but it doesn't rotate as in iOS 5 and earlier.

In plist setting I've set only 1 Portrait interface orientation. If I set other - whole app will be rotated.

Timur Mustafaev
  • 4,869
  • 9
  • 63
  • 109

7 Answers7

45

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. I have an example here:

https://stackoverflow.com/a/12522119/1575017

Community
  • 1
  • 1
rocky
  • 3,521
  • 1
  • 23
  • 31
  • You can also specify the orientations per device. i.e. allow particular rotations on the iPad, but keep the iPhone orientation locked. – Andrew Kozlik Nov 09 '12 at 15:57
13

Ough! A half of a day spent, and the problem solved! He he.

As the documentation above says, this is really it! The core points are:

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.

So, any time something with root controller changes, the system asks app delegate "So, what are we? Rotating or not?"

If "rotating":

the supported orientations are retrieved only if this view controller returns YES from its shouldAutorotate method

then system asks our app delegate for

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {    

    return ...;
}

That's really pretty simple.

How to determine when should we allow Portrait or Landscape etc - is up to you. Testing for root controller didn't work for me because of some points, but this works:

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {    

    return self.fullScreenVideoIsPlaying ?
        UIInterfaceOrientationMaskAllButUpsideDown :
        UIInterfaceOrientationMaskPortrait;
}

The property "fullScreenVideoIsPlaying" is set up by me manually whenever I need that.

The only other important thing to be careful is the enum. As it says in docs ... (read carefully above iPad/iPhone thing). So, you can play with those as you need.

Another tiny thing was some buggy behaviour after closing the player controller. There was one time when it did not change the orientation, but that happened once and in some strange way, and only in simulator (iOS 6 only, of course). So I even could not react, as it happened unexpectedly and after clicking fast on some other elements of my app, it rotated to normal orientation. So, not sure - might be some delay in simulator work or something (or, really a bug :) ).

Good luck!

tipycalFlow
  • 7,594
  • 4
  • 34
  • 45
Agat
  • 4,577
  • 2
  • 34
  • 62
  • Oh! And just forgotten. I did not change anything in my plist relatively to the orientation! I have only portrait one allowed in there! – Agat Nov 07 '12 at 23:08
  • 1
    Hi! I did exactly the same but with the difference, that it doesn't change the orientation back to portrait mode after dismissing the landscape view controller... Is there probably anything I forgot? Do you have a simple example project you could provide? – cldrr Nov 21 '12 at 15:19
  • Sorry, haven't see a notification about the comment... I have no separate code but it really seems like you've missed some small thing. Do you have also this method implemented?: **- (BOOL)shouldAutorotate** Because as documentation says: "_Moreover, the supported orientations are retrieved only if this view controller returns YES from its shouldAutorotate method._" – Agat Nov 29 '12 at 16:48
  • Excellent solution. The self.fullScreenVideoIsPlaying to detect if it should rotate or not is what solved this for me. – AndyDunn Dec 10 '13 at 22:29
7

I had the same problem with my app.

How the rotation in iOS 6 work is that.

=> when ever you are using UINavigationCOntroller the method in AppDelegate

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window    
{
   return 
}

decides whether to rotate or not.

=> when the view is presented in the Modal presentation style the method

- (BOOL)shouldAutorotate

which is inside the viewController for that view triggers the method in the appDelegate. And as 1st case appDelegate decides to rotate or not.

My Solution::

What I did for Modal presentation was that. Created a flag in app delegate.

when ever the flag is YES it rotates to Landscape and else its only Portrait.

- (NSUInteger)application:(UIApplication*)application
supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
    if(self.shouldRotate ) //shouldRotate is my flag
    {
        self.shouldRotate = NO;
        return (UIInterfaceOrientationMaskAll);
    }
    return (UIInterfaceOrientationMaskPortrait);
}

And to toggle between rotations

- (BOOL)shouldAutorotate
{
    YourAppDelegate *mainDelegate = (YourAppDelegate*)[[UIApplication sharedApplication]delegate];
    mainDelegate.shouldRotate = YES;

    return YES;
}

Note: This works is only for view that are Modely Presented. Using Flag, not a good coding practice.

Vipin Johney
  • 1,315
  • 14
  • 21
3

You can also subclass UITabBarController to make it ask its children about the shouldAutorotate and supportedInterfaceOrientation like this:

@implementation MyTabBarController

-(BOOL)shouldAutorotate
{
    return [self.selectedViewController shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [self.selectedViewController supportedInterfaceOrientations];
}

@end

Then you just use your custom container in place of the standard one and it works! just tested.

Serge Kutny
  • 89
  • 1
  • 5
2

Unfortunately you'll need to turn on all orientations in your plist and use supportedInterfaceOrientations on all the view controllers you don't want to rotate. (In your case everything but the video player.)

Anthony
  • 2,867
  • 1
  • 17
  • 17
  • 1
    This is somewhat true (and it did work for me)... but from reading http://fostah.com/ios/2012/09/27/ios6-orientation-handling.html it is clear that (for instance) you can leave the plist as only supporting portrait, but then implement the supportedInterfaceOrientationsForWindow method in the app delegate. In my case I had a movie player view that needed all orientations, but the rest of the app was portrait. – cclogg Nov 06 '12 at 08:04
1

Try this,

If TabBarController is RootViewController for window, Then Create Custom Class which inherits TabBarController say CustomTabBarController.h

Add Below method in CustomTabBarController.h

-(NSUInteger)supportedInterfaceOrientations // Must return Orientation Mask

Finally Call Below in AppDelegate.m

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window  {
   if( [self.window.rootViewController supportedInterfaceOrientations]!=0) 
     {
        return [self.window.rootViewController supportedInterfaceOrientations];
    }
    return UIInterfaceOrientationMaskAll;
}
Vinay
  • 539
  • 1
  • 4
  • 11
0

I found the easiest way to set this up is to use the "supported interface orientations" buttons which you can see if you look at Targets....Summary Tab (under iPhone/iPad Deployment info).

Its basically a GUI to set the plist file

Tim
  • 5,767
  • 9
  • 45
  • 60
  • Yep. I found this the quickest way to fix the rotation issues for ios5 developed apps developed on ios 6. I probably should have been a little more verbose. thanks – Tim Oct 31 '12 at 15:33