8

I want to only support vertical orientation throughout all the view controllers of my iOS app. However, I embed a YouTube video in one of my view controllers, and when that video is selected to take up the full screen, I want the user to be able to orient his/her phone horizontally so the video expands to take the full screen.

EDIT: I tried using the following code from Autorotate in iOS 6 has strange behaviour:

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

return self.fullScreenVideoIsPlaying ?
    UIInterfaceOrientationMaskAllButUpsideDown :
    UIInterfaceOrientationMaskPortrait;

}

and in my view controller that presents the UIWebView/YouTube frame, I have this code in my viewDidLoad:

[[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(windowNowVisible:)
     name:UIWindowDidBecomeVisibleNotification
     object:self.view.window
];

- (void)windowNowVisible:(NSNotification *)notification
{
    AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
    appDelegate.fullScreenVideoIsPlaying = !(appDelegate.fullScreenVideoIsPlaying);
}

However, when the user presses done on the fullscreen YouTube video, if he/she still has the phone horizontally, then the presenting view controller also stays horizontal (I want the present view controller to be portrait). It's a race on the fullSreenVideoIsPlaying variable which isn't updating fast enough so that my presenting view controller is portrait.

Any feedback on how to achieve this would be greatly appreciated.

Thanks!

Community
  • 1
  • 1
Rohan Agarwal
  • 2,167
  • 1
  • 24
  • 34
  • You may read - http://buddingdevelopers.com/autorotation-in-ios/ Autorotation is clearly explained here. – Xcoder May 03 '13 at 05:56
  • possible duplicate: http://stackoverflow.com/questions/13580753/mpmovieplayercontroller-rotating-in-full-screen-while-the-parent-view-controller – john.k.doe May 09 '13 at 04:46

2 Answers2

21

Figured out a solution by molding together a few solutions I've found on StackOverflow.

Instead of using this notification

 [[NSNotificationCenter defaultCenter]
      addObserver:self
      selector:@selector(windowNowVisible:)
      name:UIWindowDidBecomeVisibleNotification
      object:self.view.window
 ];

I use the following notifications

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(youTubeStarted:) name:@"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(youTubeFinished:) name:@"UIMoviePlayerControllerWillExitFullscreenNotification" object:nil];

with the implementations

 -(void) youTubeStarted:(NSNotification*) notif {
     AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
     appDelegate.fullScreenVideoIsPlaying = YES;
}
 -(void) youTubeFinished:(NSNotification*) notif {
     AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
     appDelegate.fullScreenVideoIsPlaying = NO;
 }

and in my AppDelegate, I have

 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
     NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
     if (self.fullScreenVideoIsPlaying) {
         return UIInterfaceOrientationMaskAllButUpsideDown;
     }
     else {        
         if(self.window.rootViewController){
             UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
             orientations = [presentedViewController supportedInterfaceOrientations];
     }
return orientations;
 }

and in my view controllers, I have

 -(BOOL) shouldAutorotate {
     return NO;
 }
 -(NSUInteger)supportedInterfaceOrientations{
     return UIInterfaceOrientationMaskPortrait;
 }
 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
     return UIInterfaceOrientationPortrait;
 }
Rohan Agarwal
  • 2,167
  • 1
  • 24
  • 34
  • 2
    Just keep in mind that using private notifications (`UIMoviePlayerControllerDidEnterFullscreenNotification` and `UIMoviePlayerControllerWillExitFullscreenNotification`) could break in future iOS releases or cause an App Store rejection. – jszumski May 06 '13 at 01:39
  • Ok thanks! Do you know of any other notification I could use? – Rohan Agarwal May 06 '13 at 08:11
  • Unfortunately the SDK doesn't provide any as of iOS 6. – jszumski May 06 '13 at 11:54
  • 3
    What I ended up doing is returning UIInterfaceOrientationMaskAllButUpsideDown in the delegate method, and then subclassing UITabBarController (my root view controller) to return UIInterfaceOrientationMaskPortrait in -supportedInterfaceOrientations. That way, video can play in landscape, but all the child view controllers of the tab bar controller only support portrait. – EJV May 06 '13 at 19:52
  • How can i make portrait only? – Nam Vu Jun 21 '13 at 12:12
  • Sorry my mistake,i want landscape only for youtube player. – Nam Vu Jun 21 '13 at 12:24
  • How'd you hook up the notifications? – shim Jul 21 '13 at 23:49
  • Rohan:dude you are my hero...u saved my day – user578386 Sep 23 '13 at 08:42
  • @jszumski's comment makes me nervous, but I have exhausted my search for better solutions. – Morkrom Dec 01 '13 at 04:10
6

I've encountered the very same problem before, and the best solution I could find that worked under iOS 5.x and 6.x was to present the video controller in a modal view.

The modal view is a UINavigationController that wraps the video controller and responds with UIInterfaceOrientationMaskAll in supportedInterfaceOrientations. In the modal view's viewWillAppear:, I flip fullScreenVideoIsPlaying to YES and set it to NO in viewWillDisappear:. This arrangement will keep the underlying view controllers in portrait while allowing the modal view to rotate as the user sees fit.

jszumski
  • 7,430
  • 11
  • 40
  • 53
  • 1
    thanks for your response..had a quick follow-up question. Right now, my UIWebView of the youtube video is a small cell (200x100) in the middle of my presenting view controller. When it's selected to play, how do I present the video in a modal view controller? In other words, how do I get a callback that the user pressed the play button in the UIWebView? – Rohan Agarwal May 05 '13 at 00:44
  • The video player that comes from the web view will respect its parent's rotation settings, so you'll have to make your "presenting view controller" a modal view. – jszumski May 05 '13 at 02:01
  • I understand that the video player will respect its parent's rotation settings; however, my issue is that I don't want the present view controller to be able to rotate horizontally. Only the video player that it presents should be able to rotate horizontally – Rohan Agarwal May 05 '13 at 03:08
  • Specifically, how do you "present the video controller in a modal view"? Is there a way I can get a pointer to the video controller? – Rohan Agarwal May 05 '13 at 03:12
  • Unfortunately there isn't a way to get a reference to the web view's `MPMoviePlayerController`, I meant controller as in the view controller containing your 200x100 web view. You could present a full-size `UIWebView` in a modal controller and have it auto play (`mediaPlaybackRequiresUserAction = NO`). – jszumski May 05 '13 at 03:14
  • thanks this is starting to make sense to me. do you have any code that shows how to do this? My issue specifically is, how do I present a modal view that is a uinavigationcontroller that wraps the video controller? Since the youtube video is in a webview and I don't have any callbacks, I don't know when the user touches play in the webview. Also, the uiwebview of the embedded youtube video is in a uicollectionviewcell (not sure if that's relevant) – Rohan Agarwal May 06 '13 at 00:39
  • Thanks for your help, but I've found a new solution which I posted here – Rohan Agarwal May 06 '13 at 00:59