如何让AVPlayerViewController以编程方式进入全屏?

ika*_*ver 22 objective-c ios swift ios8

我试图让AVPlayerViewController以编程方式进入全屏模式,来自"嵌入式"模式,但是这似乎不可能与已发布的API一起使用.

我缺少一种解决方法吗?我有兴趣获得与用户按下控件右下角的全屏按钮时获得的动画相同的动画.

使用MPMoviePlayerController不是一个可行的选择,因为我可能一次播放多个视频.

谢谢.

Dan*_*l J 14

AVPlayerViewController是UIViewController的子类,因此它可以像任何其他视图控制器子类一样呈现.你能用presentViewController:animated:completion吗?

self.avPlayerController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:self.avPlayerController animated:YES completion:nil];
Run Code Online (Sandbox Code Playgroud)

然后在左上角显示"完成"按钮.


Tod*_*ddH 12

针对iOS 11进行了更新

没有受支持的方式以编程方式使用AVPlayerViewController全屏(在我看来有点疏忽).

但是,AVPlayerViewController确实包含一个私有方法.你必须自己决定是否要使用它,因为你不应该使用私有方法.

AVPlayerViewController + Fullscreen.h

#import <AVKit/AVKit.h>

@interface AVPlayerViewController (Fullscreen)

-(void)goFullscreen;

@end
Run Code Online (Sandbox Code Playgroud)

AVPlayerViewController + Fullscreen.m

#import "AVPlayerViewController+Fullscreen.h"

@implementation AVPlayerViewController (Fullscreen)

-(void)goFullscreen {
    NSString *selectorForFullscreen = @"transitionToFullScreenViewControllerAnimated:completionHandler:";
    if (@available(iOS 11.3, *)) {
        selectorForFullscreen = @"transitionToFullScreenAnimated:interactive:completionHandler:";
    } else if (@available(iOS 11.0, *)) {
        selectorForFullscreen = @"transitionToFullScreenAnimated:completionHandler:";
    }
    SEL fsSelector = NSSelectorFromString([@"_" stringByAppendingString:selectorForFullscreen]);
    if ([self respondsToSelector:fsSelector]) {
        NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:fsSelector]];
        [inv setSelector:fsSelector];
        [inv setTarget:self];

        NSInteger index = 2; //arguments 0 and 1 are self and _cmd respectively, automatically set
        BOOL animated = YES;
        [inv setArgument:&(animated) atIndex:index];
        index++;

        if (@available(iOS 11.3, *)) {
            BOOL interactive = YES;
            [inv setArgument:&(interactive) atIndex:index]; //arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation
            index++;
        }

        id completionBlock = nil;
        [inv setArgument:&(completionBlock) atIndex:index];
        [inv invoke];
    }
}

@end
Run Code Online (Sandbox Code Playgroud)


小智 8

作为 iOS 14 对 ToddH 答案的一点更新:要调用的私有 APIenterFullScreenAnimated:completionHandler:是. 所以这里有一个AVPlayerViewController的扩展来进入全屏。

extension AVPlayerViewController {
    func enterFullScreen(animated: Bool) {
        perform(NSSelectorFromString("enterFullScreenAnimated:completionHandler:"), with: animated, with: nil)
    }
    func exitFullScreen(animated: Bool) {
        perform(NSSelectorFromString("exitFullScreenAnimated:completionHandler:"), with: animated, with: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

此实现不提供完成回调。如果将 Swift 闭包传递给参数completionHandler,它会在底层 Obj-C API 中崩溃。我还没有研究如何通过关闭使其发挥作用。


Rom*_*mov 7

在iOS11中有2个新属性AVPlayerViewController:entersFullScreenWhenPlaybackBeginsexitsFullScreenWhenPlaybackEnds.您可以在播放开始后立即启用全屏模式,并在播放结束时使用这些属性将其禁用.如果您需要在延迟一段时间后启用全屏模式,则可以使用私有API方法,如ToddH其答案中所述.但是在iOS11 _transitionToFullScreenViewControllerAnimated:completionHandler:方法中不再可用,有相同的方法调用_transitionToFullScreenAnimated:completionHandler:.第二种方法接受与第一种方法相同的参数.

我可以举例说明如何使用它.首先,您需要AVPlayerViewController在您的UIViewController:中创建实例:

private let playerController : AVPlayerViewController = {

    if let urlForPlayer = URL(string: "your_video_url") {

        $0.player = AVPlayer(url: urlForPlayer)
    }
    return $0
} (AVPlayerViewController())
Run Code Online (Sandbox Code Playgroud)

然后,您需要为AVPlayerViewController设置视图并将其添加到当前控制器视图中.功能setupAVplayerController可以为您做到:

private func setupAVplayerController() {

    self.addChildViewController(self.playerController)
    self.playerController.view.frame = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0)
    self.view.addSubview(self.playerController.view)
    self.playerController.didMove(toParentViewController: self)
}
Run Code Online (Sandbox Code Playgroud)

功能enterFullscreen强制全屏模式AVPlayerViewController:

private func enterFullscreen(playerViewController:AVPlayerViewController) {

    let selectorName : String = {

        if #available(iOS 11, *) {

            return "_transitionToFullScreenAnimated:completionHandler:"
        } else {

            return "_transitionToFullScreenViewControllerAnimated:completionHandler:"
        }
    }()
    let selectorToForceFullScreenMode = NSSelectorFromString(selectorName)
    if playerViewController.responds(to: selectorToForceFullScreenMode) {

            playerViewController.perform(selectorToForceFullScreenMode, with: true, with: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您需要在需要的地方调用所有这些功能,例如viewDidAppear:

override func viewDidAppear(_ animated: Bool) {

    super.viewDidAppear(animated)

    //Your code

    self.setupAVplayerController()
    self.playerController.player?.play()
    DispatchQueue.main.asyncAfter(deadline: .now() + 10) {

        self.enterFullscreen(playerViewController:self.playerController)
    }
}
Run Code Online (Sandbox Code Playgroud)

不要忘记这个解决方案基于不建议使用的私有API调用.


小智 6

更新:ToddH 答案的 Swift 4 版本:

private func enterFullscreen(playerViewController: AVPlayerViewController) {

    let selectorName: String = {
        if #available(iOS 11.3, *) {
            return "_transitionToFullScreenAnimated:interactive:completionHandler:"
        } else if #available(iOS 11, *) {
            return "_transitionToFullScreenAnimated:completionHandler:"
        } else {
            return "_transitionToFullScreenViewControllerAnimated:completionHandler:"
        }
    }()
    let selectorToForceFullScreenMode = NSSelectorFromString(selectorName)

    if playerViewController.responds(to: selectorToForceFullScreenMode) {
        playerViewController.perform(selectorToForceFullScreenMode, with: true, with: nil)
    }
}
Run Code Online (Sandbox Code Playgroud)