我正在尝试通过编程的方式将 AVPlayerViewController 从"嵌入式"模式切换到全屏模式,但是通过公开的API似乎不可能实现。
有没有我错过的解决方法? 我想获取与用户按控件右下角的全屏按钮时相同的动画。
使用MPMoviePlayerController不是可行的替代方案,因为可能会同时播放多个视频。
谢谢。
我正在尝试通过编程的方式将 AVPlayerViewController 从"嵌入式"模式切换到全屏模式,但是通过公开的API似乎不可能实现。
有没有我错过的解决方法? 我想获取与用户按控件右下角的全屏按钮时相同的动画。
使用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
DispatchQueue.main.async { isFullscreen = playerViewController.view.bounds != playerViewController.contentOverlayView?.bounds ... }
- ToddH更新: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)
}
}
AVPlayerViewController
有两个新属性:entersFullScreenWhenPlaybackBegins
和exitsFullScreenWhenPlaybackEnds
。您可以使用这些属性在播放开始后立即启用全屏模式,并在播放结束时禁用它。如果您需要在一定延迟后启用全屏模式,则可以像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)
}
}
enterFullScreenAnimated: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中崩溃。我没有研究如何传递闭包使其工作。
if(fullscreen)
{
[self.avPlayerController
setVideoGravity:AVLayerVideoGravityResizeAspectFill];
}
else
{
[self.avPlayerController
setVideoGravity:AVLayerVideoGravityResizeAspect];
}
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
添加为子视图控制器。
然后,您需要先删除子视图控制器,然后再将其作为全屏控制器呈现,并将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())
})
}
UIViewController.attemptRotationToDeviceOrientation()
来代替设置 playerVC.view
的约束。 - Tuan LuongentersFullScreenWhenPlaybackBegins
设置为 true,我也无法在全屏模式下开始播放。 - funkybro很简单,只需设置
playerViewController.videoGravity = .resizeAspectFill
它就会全屏显示:)