Question

The app I'm working on is portrait oriented, but when a video is running (it is embed in a webview), I need to re-orient the video in landscape mode. How should I do that? I found a solution, which worked just fine until days ago :). I believe it's because iOS 7 updates, but I'm not sure. So, this is what I previously used, but it is not working anymore because window and class name are always nil.

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

id presentedViewController = [window.rootViewController presentedViewController];
NSString *className = presentedViewController ? NSStringFromClass([presentedViewController class]) : nil;

if (window && [className isEqualToString:@"MPInlineVideoFullscreenViewController"]) {
    return UIInterfaceOrientationMaskAll;
} else {
    return UIInterfaceOrientationMaskPortrait;
}
Was it helpful?

Solution

I found a solution by myself, finally! I implemented the following method in AppDelegate and it worked. My problem was that, at first, I didn't check the right view controller.

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

NSString *className = NSStringFromClass([window class]);
if ([((UINavigationController *)window.rootViewController) respondsToSelector:@selector(visibleViewController)]) {
    className = NSStringFromClass([((UINavigationController *)window.rootViewController).visibleViewController class]);
}

if ([className isEqualToString:@"MPFullscreenWindow"] || [className isEqualToString:@"MPInlineVideoFullscreenViewController"]) {
    return UIInterfaceOrientationMaskAll;
} else if  (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
    return UIInterfaceOrientationMaskLandscape;
} else {
    return UIInterfaceOrientationMaskPortrait;
} 

OTHER TIPS

Here's a solution that will allow rotation on any additional windows presented in the iPhone app (such as a vide player) but remain landscape in an iPad app. Place it in your app delegate.

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


if  (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){
    return UIInterfaceOrientationMaskLandscape;
} else {

    if (window == self.window
        || ![window isMemberOfClass:[UIWindow class]]) {
        return UIInterfaceOrientationMaskPortrait;
    }

    if ([window isEqual:[[UIApplication sharedApplication] windows][1]]) {
        // Rotate the secondary window.
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }

    return UIInterfaceOrientationMaskPortrait;
}

So I figured I'd share what my solution was. Actually branching off of the OP question, just modified it. Works for me on iOS 7 and 8.

My approach was different as I have a toggle switch in another view controller that enables portrait or landscape.

Anyways, here it is.

UPDATED:

Ok so the previous method broke the launch screen. Example: If you have your device in landscape, and launched but it's a portrait app, it will rotate, BUT, the window will get cut in half. Pain in the butt esp if you have some nice loading screens going on. Anyways, the replaced code below fixes that AND allows video rotation. Obviously not everybody will be using a rotation switch, just adjust accordingly.

//Allow video only rotation in portrait mode.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{

    //Switch for Rotation
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"Rotation"];

    if (switchOn) {
        window.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
        [window setFrame:[[UIScreen mainScreen] bounds]]; //Add
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }
    else {
        id presentedViewController = [window.rootViewController presentedViewController];
        NSString *className = presentedViewController ? NSStringFromClass([presentedViewController class]) : nil;

        if ((window && [className isEqualToString:@"MPInlineVideoFullscreenViewController"]) ||
            [className isEqualToString:@"MPMoviePlayerViewController"] ||
            [className isEqualToString:@"AVFullScreenViewController"]) {

            window.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
            [window setFrame:[[UIScreen mainScreen] bounds]]; //Add
            [window makeKeyAndVisible];

            return UIInterfaceOrientationMaskAllButUpsideDown;
        }

        window.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
        [window setFrame:[[UIScreen mainScreen] bounds]]; //Add
        return UIInterfaceOrientationMaskPortrait;
    }

    self.window.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
    [self.window setFrame:[[UIScreen mainScreen] bounds]]; //Add
    [self.window makeKeyAndVisible];
}

UPDATED AGAIN:

So the previous edit I laid out had a weird flicker of the view below the movie player. This seems to have fixed that. Tested on 6+ device, and iOS 7/8 in the simulator.

Hope this helps somebody.

Swift 3, I sorted out on this way (your info.plist / project settings can have ONYL the portrait orientation checked) :

// MARK: - Orientation

extension AppDelegate {
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {

        // Let webView video to be rotated
        if window != self.window {
            return window?.rootViewController?.supportedInterfaceOrientations ?? .all;
        }

        // All other screens are portrait
        return .portrait;
    }

}

Try It....

-(BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return YES;
}

If you don't want your UIViewController to be able to rotate when the video isn't on the screen. Use this--

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(webView && webView.superView) return YES;
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}

This is very similar to how I solved for iOS 7, but this doesn't work for iOS 8. MPFullscreenWindow is no longer returned and Xcode complains about breaking constraints.

My solution seems to be fairly general, and takes care of some weird behavior on iOS 7 where window sometimes passed in as nil.

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        return UIInterfaceOrientationMaskAll;
    }
    else
    {
        // when dismissing a view controller, the view controller being returned to isn't in control of the orientiation
        // (shouldAutorotate and supportedInterfaceOrientations seem to be called, but they aren't observed then,
        // rather only when the device is rotated after that view is fully showing)
        // instead, the result of this method only is what's observed
        // we could return different values depending on which view controller is frontmost, but currently it seems
        // good enough to call supportedInterfaceOrientations of the frontmost view controller and return that

        // on ios7, critical calls to this method are often passed window=nil, in that case use self.window instead
        UIViewController *frontViewController = window ? window.rootViewController : self.window.rootViewController;

        // special case only when transitioning to or from a presented view controller
        if (frontViewController.presentedViewController &&
            (frontViewController.presentedViewController.isBeingDismissed || frontViewController.presentedViewController.isBeingPresented))
        {
            if (frontViewController.presentedViewController && !frontViewController.presentedViewController.isBeingDismissed) {
                frontViewController = frontViewController.presentedViewController;
            }
            if ([frontViewController isKindOfClass:[UINavigationController class]]) {
                frontViewController = ((UINavigationController *)frontViewController).topViewController;
            }

            // return whatever the front view controller's supportedInterfaceOrientations returns, since it normally is ignored for some reason
            return [frontViewController supportedInterfaceOrientations];
        }
        else
        {
            // return this normally, this gets intersected with the result of the front view controller's supportedInterfaceOrientations
            return UIInterfaceOrientationMaskAllButUpsideDown;
        }
    }
}
=> Put below method inside your  AppDelegate class, it allow to play video in landscape mode even when device orientation is locked to portrait mode only:


- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)windowx
{
    if ([[self.window.rootViewController presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]] ||
    [[self.window.rootViewController presentedViewController] isKindOfClass:NSClassFromString(@"MPInlineVideoFullscreenViewController")])
    {
        if ([self.window.rootViewController presentedViewController].isBeingDismissed)
        {
            return UIInterfaceOrientationMaskPortrait;
        }
        else
        {
            return UIInterfaceOrientationMaskAllButUpsideDown;
        }
    }
    else
    {
        return UIInterfaceOrientationMaskPortrait;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top