簡體   English   中英

如何以編程方式將 AVPlayerViewController go 全屏顯示?

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

我正在嘗試以編程方式將AVPlayerViewController go 從“嵌入式”模式變為全屏模式,但是對於已發布的 API 這似乎是不可能的。

有沒有我缺少的解決方法? 我有興趣獲得與用戶按下控件右下角的全屏按鈕時獲得的相同的 animation。

使用 MPMoviePlayerController 不是一個可行的選擇,因為我可能一次播放多個視頻。

謝謝。

AVPlayerViewController 是 UIViewController 的子類,因此它可以像任何其他視圖控制器子類一樣呈現。 你能使用presentViewController:animated:completion嗎?

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

然后在左上角顯示“完成”按鈕。

針對 iOS 11 更新

沒有支持以編程方式使用 AVPlayerViewController 全屏顯示的方法(我認為有點疏忽)。

但是, AVPlayerViewController 確實包含一個私有方法,可以做到這一點。 鑒於您不應該調用私有方法,您必須自己決定是否要使用它。

AVPlayerViewController+Fullscreen.h

#import <AVKit/AVKit.h>

@interface AVPlayerViewController (Fullscreen)

-(void)goFullscreen;

@end

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

在 iOS11 中, AVPlayerViewController有 2 個新屬性: entersFullScreenWhenPlaybackBeginsexitsFullScreenWhenPlaybackEnds 您可以在播放開始后立即啟用全屏模式,並在播放結束時禁用這些屬性。 如果您需要在延遲一段時間后啟用全屏模式,您可以使用ToddH他的回答中提到的私有 API 方法。 但是在 iOS11 中_transitionToFullScreenViewControllerAnimated:completionHandler:方法不再可用,有相同的方法稱為_transitionToFullScreenAnimated:completionHandler: 第二種方法接受與第一種方法相同的參數。

我可以展示一個如何使用它的例子。 首先,您需要在UIViewController創建AVPlayerViewController實例:

private let playerController : AVPlayerViewController = {

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

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

然后您需要為 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)
}

函數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)
    }
}

現在您需要在需要的地方調用所有這些函數,例如在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)
    }
}

不要忘記,這個基於私有 API 調用的解決方案是不推薦使用的。

更新: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)
    }
}

作為 ToddH 答案的 iOS 14 小更新:要調用的私有 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)
    }
}

此實現不提供完成回調。 如果您將 Swift 閉包傳遞給completionHandler參數,它會在底層 Obj-C API 中崩潰。 我還沒有研究如何通過閉包使其工作。

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)
        }
    }
}

你可以只設置 AVPlayerViewController 的videoGravity屬性。

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

我不需要使用任何受限代碼。

為此,我假設您已將AVPlayerViewController添加為子視圖控制器。

然后為此,您首先必須刪除子視圖控制器,然后將其再次顯示為全屏控制器,並將AVPlayer視圖正確附加到其父視圖。

這是我如何做到的。 請注意,我正在使用一個名為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())
        })
    }

對於“嵌入式” AVPlayerViewController實例,很容易以編程方式讓它在全屏模式下開始播放,而無需破解任何內容(調用私有方法)。 您只需將其entersFullScreenWhenPlaybackBegins屬性設置為 true。

您需要將控制器作為子 VC 添加到主 VC,基本上就是這樣。 viewDidAppear(_:)您需要在控制器的player屬性上調用play()方法 - 播放將自動以全屏方式開始。

對於這些棘手的 API,通常最好檢查 Apple 示例代碼; 我認為這可能對很多 AVPlayer 用例有用: 在 iOS 中使用 AVKit

非常簡單,只需設置playerViewController.videoGravity =.resizeAspectFill

它全屏顯示:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM