简体   繁体   English

如何以编程方式将 AVPlayerViewController go 全屏显示?

[英]How to make a AVPlayerViewController go to fullscreen programmatically?

I'm trying to make a AVPlayerViewController go to full screen mode programmatically, coming from "embedded" mode, however this does not appear to be possible with the published API.我正在尝试以编程方式将AVPlayerViewController go 从“嵌入式”模式变为全屏模式,但是对于已发布的 API 这似乎是不可能的。

Is there a workaround that I'm missing?有没有我缺少的解决方法? I'm interested in obtaining the same animation to the one that you get when the user presses the full screen button on the bottom right of the controls.我有兴趣获得与用户按下控件右下角的全屏按钮时获得的相同的 animation。

Using MPMoviePlayerController is not a viable alternative since I might have more than one video playing at a time.使用 MPMoviePlayerController 不是一个可行的选择,因为我可能一次播放多个视频。

Thanks.谢谢。

AVPlayerViewController is a subclass of UIViewController, so it is presentable like any other view controller subclass. AVPlayerViewController 是 UIViewController 的子类,因此它可以像任何其他视图控制器子类一样呈现。 Are you able to use presentViewController:animated:completion ?你能使用presentViewController:animated:completion吗?

self.avPlayerController.modalPresentationStyle = UIModalPresentationOverFullScreen;
[self presentViewController:self.avPlayerController animated:YES completion:nil];

This then shows the "Done" button in the top left-hand corner.然后在左上角显示“完成”按钮。

Updated for iOS 11针对 iOS 11 更新

There is no supported way to programmatically go fullscreen with AVPlayerViewController (a bit of an oversight in my opinion).没有支持以编程方式使用 AVPlayerViewController 全屏显示的方法(我认为有点疏忽)。

However, AVPlayerViewController does contain a private method that does exactly that.但是, AVPlayerViewController 确实包含一个私有方法,可以做到这一点。 You'll have to decide for yourself whether you'd want to use it or not given you're not supposed to call private methods.鉴于您不应该调用私有方法,您必须自己决定是否要使用它。

AVPlayerViewController+Fullscreen.h AVPlayerViewController+Fullscreen.h

#import <AVKit/AVKit.h>

@interface AVPlayerViewController (Fullscreen)

-(void)goFullscreen;

@end

AVPlayerViewController+Fullscreen.m 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

In iOS11 there are 2 new properties for AVPlayerViewController : entersFullScreenWhenPlaybackBegins and exitsFullScreenWhenPlaybackEnds .在 iOS11 中, AVPlayerViewController有 2 个新属性: entersFullScreenWhenPlaybackBeginsexitsFullScreenWhenPlaybackEnds You can enable full screen mode right after playback begins and disable it when playback ends with these properties.您可以在播放开始后立即启用全屏模式,并在播放结束时禁用这些属性。 If you need to enable fullscreen mode after some delay you can use private API methods as ToddH mentioned in his answer .如果您需要在延迟一段时间后启用全屏模式,您可以使用ToddH他的回答中提到的私有 API 方法。 However in iOS11 _transitionToFullScreenViewControllerAnimated:completionHandler: method is not available anymore, there is the same method called _transitionToFullScreenAnimated:completionHandler: .但是在 iOS11 中_transitionToFullScreenViewControllerAnimated:completionHandler:方法不再可用,有相同的方法称为_transitionToFullScreenAnimated:completionHandler: The second method accepts the same arguments as the first one.第二种方法接受与第一种方法相同的参数。

I can show an example how to use it.我可以展示一个如何使用它的例子。 First of all you need to create AVPlayerViewController instance in your UIViewController :首先,您需要在UIViewController创建AVPlayerViewController实例:

private let playerController : AVPlayerViewController = {

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

        $0.player = AVPlayer(url: urlForPlayer)
    }
    return $0
} (AVPlayerViewController())

Then you need to setup view for AVPlayerViewController and add it to your current controller view.然后您需要为 AVPlayerViewController 设置视图并将其添加到您当前的控制器视图中。 Function setupAVplayerController can do it for you:函数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)
}

Function enterFullscreen forces full screen mode for AVPlayerViewController :函数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)
    }
}

And now you need to call all these functions where you need it, for example in viewDidAppear :现在您需要在需要的地方调用所有这些函数,例如在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)
    }
}

Don't forget that this solution based on private API calls that is not recommended to use.不要忘记,这个基于私有 API 调用的解决方案是不推荐使用的。

UPDATE: Swift 4 version of ToddH's answer:更新: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)
    }
}

As a little iOS 14 update to ToddH's answer: the private API to call is enterFullScreenAnimated:completionHandler: .作为 ToddH 答案的 iOS 14 小更新:要调用的私有 APIenterFullScreenAnimated:completionHandler: So here's an extension on AVPlayerViewController to enter full screen.所以这里有一个关于 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)
    }
}

This implementation doesn't offer a completion callback.此实现不提供完成回调。 If you pass a Swift closure to the completionHandler parameter, it crashes in the underlying Obj-C API.如果您将 Swift 闭包传递给completionHandler参数,它会在底层 Obj-C API 中崩溃。 I haven't investigated how to pass the closure to make it work.我还没有研究如何通过闭包使其工作。

Swift 3 version for the answer of ToddH: ToddH 的 Swift 3 版本:

extension AVPlayerViewController {

    func goFullScreen() {
        let selector = NSSelectorFromString("_transitionToFullScreenViewControllerAnimated:completionHandler:")
        if self.responds(to: selector) {
            // first argument is animated (true for me), second is completion handler (nil in my case)
            self.perform(selector, with: true, with: nil)
        }
    }
}

You can just set the videoGravity property of AVPlayerViewController.你可以只设置 AVPlayerViewController 的videoGravity属性。

if(fullscreen)
{
    [self.avPlayerController 
     setVideoGravity:AVLayerVideoGravityResizeAspectFill];
}
else
{
    [self.avPlayerController 
    setVideoGravity:AVLayerVideoGravityResizeAspect];
}

I did not have the need to use any restricted code.我不需要使用任何受限代码。

For this, I am assuming that you have added the AVPlayerViewController as a child view controller.为此,我假设您已将AVPlayerViewController添加为子视图控制器。

Then for that you will first have to remove the child view controller and then present it again as a fullscreen controller as well attach the AVPlayer view properly to it's parent view.然后为此,您首先必须删除子视图控制器,然后将其再次显示为全屏控制器,并将AVPlayer视图正确附加到其父视图。

Here is how I did it.这是我如何做到的。 Please note that I am using a library called Easy Peasy for restoring the playerVC.view constraints - one can do that with proper constraints as well.请注意,我正在使用一个名为Easy Peasy的库来恢复playerVC.view约束 - 也可以通过适当的约束来做到这一点。

    @objc func fullscreenButtonClicked() {

        playerVC.willMove(toParentViewController: nil)
        playerVC.view.removeFromSuperview()
        playerVC.removeFromParentViewController()


        self.present(self.playerVC, animated: false, completion: {
            self.playerVC.view.easy.layout(Top(), Right(), Left(), Bottom())
        })
    }

For an 'embedded' AVPlayerViewController instance, it is quite easy to programmatically have it start playback in full screen mode, and without hacking anything (calling private methods).对于“嵌入式” AVPlayerViewController实例,很容易以编程方式让它在全屏模式下开始播放,而无需破解任何内容(调用私有方法)。 You just need to set its entersFullScreenWhenPlaybackBegins property to true.您只需将其entersFullScreenWhenPlaybackBegins属性设置为 true。

You need to add the controller as a child VC to the main VC, and that's basically it.您需要将控制器作为子 VC 添加到主 VC,基本上就是这样。 In viewDidAppear(_:) you need to call play() method on the controller's player property - playback will be automatically started in fullscreen.viewDidAppear(_:)您需要在控制器的player属性上调用play()方法 - 播放将自动以全屏方式开始。

It's often best to check Apple sample code for these kind of tricky APIs;对于这些棘手的 API,通常最好检查 Apple 示例代码; I think this one might be useful for a lot of AVPlayer use cases: Using AVKit in iOS .我认为这可能对很多 AVPlayer 用例有用: 在 iOS 中使用 AVKit

Its pretty simple, just set playerViewController.videoGravity =.resizeAspectFill非常简单,只需设置playerViewController.videoGravity =.resizeAspectFill

and it goes full screen:)它全屏显示:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM