MPMoviePlayerViewController | Allow landscape mode

2019-04-03 22:57发布

问题:

I'm trying to stream a video in my app. The method I've found is :

NSURL *theMovieURL = [NSURL URLWithString:self.data.trailer];
        if (theMovieURL)
        {
            self.movieController = [[MPMoviePlayerViewController alloc] initWithContentURL:theMovieURL];
            [self presentMoviePlayerViewControllerAnimated:self.movieController];
            [self.movieController.moviePlayer play];
        }

I'm not sure if it's the most conventional, but it works.

The problem is that I can't figure out how to allow the landscape mode, for the video only. Should I use something like shouldAutorotate or shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation , and how ?

FYI, the entire app allows only the portrait mode.

Thanks for your help.

回答1:

shouldAutoRotate is deprecated as of iOS 6 and should be avoided unless you're going for < 6 .

Instead, you'd want to override the supportedInterfaceOrientations and preferredInterfaceOrientationForPresentation methods.

In this case, if you don't want to subclass the media player you could override a method in the app delegate like so:

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    if ([[self.window.rootViewController presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]])
    {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }
    else
    {
        return UIInterfaceOrientationMaskPortrait;
    }
}


回答2:

@peko says correct way. when user exits from fullscreen video, this method called again with MPMoviePlayerViewController class. you should check it is dismissed or not, if you don't, when user exit from video, main window will stay in landscape mode, and also you forgot MPInlineVideoFullscreenViewController class. when you use embed player (not fullscreen) it is called with that class name.

I did it like that. it works for me.

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


回答3:

The movie player might not be the first presented view controller, so you should do something like this

- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    UIViewController* playerController = self.window.rootViewController.presentedViewController;
    while (playerController && ![playerController isKindOfClass:[MPMoviePlayerViewController class]]) {
        playerController = playerController.presentedViewController;
    }
    if (playerController && !playerController.isBeingDismissed) {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }
}

Although MPMoviePlayerViewController has been deprecated so you should use AVPlayerViewController instead and check its class too in this loop.



回答4:

The best way so far is to implement this AppDelegate function and check if the rootViewController has a child of type AVPlayerViewController or MPMoviePlayerViewController then you return [.portrait, .landscapeLeft, .landscapeRight] and else .portrait.

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let _ = UIApplication.shared.keyWindow?.rootViewController?.childViewControllers.first as? AVPlayerViewController {
        return [.portrait, .landscapeLeft, .landscapeRight]
    }
    return .portrait
}

You should check on the keyWindow of UIApplication because apple presents this viewController in a another UIWindow so if you try to do that check on the window that is declared in the AppDelegate this won't work so be careful.