最近开始研究iOS14画中画功能的实现,最终分别通过使用AVPlayerViewController构建播放器和AVPlayerLayer构建播放器,分别实现相应的画中画的功能
实现的效果图为:
项目的demo地址为:
demo地址
AVPlayerViewController实现画中画的功能
画中画功能的实现主要还是阅读苹果开发文档
开发文档中提到了AVPlayerViewController构建播放器时,这个是最简单的,只需要申请相应的权限,系统自带的控制器会带有开启画中画的按钮
首先,我们先使用AVPlayerViewController搭建一个播放视频的基本界面,(项目中对应的文件名是FirstViewController)
项目中使用的视频链接为:https://youku.cdn4-okzy.com/20200618/8130_4b8b9a06/1000k/hls/index.m3u8(是一个m3u8文件)
首先定义相应的属性和懒加载属性
@property (nonatomic, strong) AVPlayerViewController *avPlayer;//播放器
@property (nonatomic, strong) AVPlayer *player;//播放器播放的项目
@property (nonatomic, strong) UIButton *playButton;//播放按钮(也可以不用这个)
相应的懒加载为:
- (AVPlayerViewController *)avPlayer {
if (_avPlayer) {
return _avPlayer;
}
_avPlayer = [[AVPlayerViewController alloc] init];
_avPlayer.showsPlaybackControls = YES;
//AVPlayerViewController开启画中画只需要设置这个属性为YES即可(也可以不设置,默认为YES)
_avPlayer.allowsPictureInPicturePlayback = YES;
return _avPlayer;
}
- (AVPlayer *)player {
if (_player) {
return _player;
}
_player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:@"https://youku.cdn4-okzy.com/20200618/8130_4b8b9a06/1000k/hls/index.m3u8"]];
return _player;
}
- (UIButton *)playButton {
if (_playButton) {
return _playButton;
}
_playButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[_playButton setTitle:@"播放" forState:UIControlStateNormal];
[_playButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_playButton addTarget:self action:@selector(playVideo) forControlEvents:UIControlEventTouchUpInside];
return _playButton;
}
//自己添加的按钮的点击事件
- (void)playVideo {
NSLog(@"开始播放视频");
[self.avPlayer.player play];
}
在viewDidLoad中将播放器添加到view上
- (void)viewDidLoad {
[super viewDidLoad];
self.avPlayer.view.frame = CGRectMake(0, 0, self.view.bounds.size.width, 300);
[self.view addSubview:self.avPlayer.view];
self.avPlayer.player = self.player;
self.playButton.frame = CGRectMake((self.view.bounds.size.width - 100) / 2, 320, 100, 50);
[self.view addSubview:self.playButton];
}
运行就可以发现,可以播放视频
但是没有画中画的按钮,因为我们没有申请权限,另外,画中画开启前我们需要判断当前设备是否支持画中画的功能
在viewDidLoad中添加以下代码即可
if ([AVPictureInPictureController isPictureInPictureSupported]) {
NSLog(@"该设备支持画中画功能");
//开启画中画权限
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error) {
NSLog(@"请求权限失败的原因为%@",error);
}
} else {
NSLog(@"该设备不支持画中画功能");
}
最终,我们得到的效果图为:
AVPlayerLayer实现画中画的功能
首先,和原先一样,我们需要搭建一个能够播放视频的项目(在demo中文件名为secondViewController)
对于AVPlayerLayer是继承与CALayer,这个就是在view上添加一层layer用于播放视频。
(注意:这种方法播放视频没有系统提供控制栏,控制栏需要自己定义,下面我是定义了几个按钮)
对于AVPlayerLayer,我们打开苹果开发者文档,里面有给出其相应的封装例子,我们直接原样使用即可
在项目中,我们使用同样的代码,将其命名为playView
下面我们开始搭建基本的播放项目
定义相应的属性
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) PlayerView *playerView;
@property (nonatomic, strong) UIButton *playButton;//播放按钮
@property (nonatomic, strong) UIButton *pauseButton;//暂停按钮
@property (nonatomic, strong) UIButton *startPipButton;//开启画中画按钮
实现相应的懒加载
- (AVPlayer *)player {
if (_player) {
return _player;
}
_player = [[AVPlayer alloc] initWithURL:[NSURL URLWithString:@"https://youku.cdn4-okzy.com/20200618/8130_4b8b9a06/1000k/hls/index.m3u8"]];
return _player;
}
- (PlayerView *)playerView {
if (_playerView) {
return _playerView;
}
_playerView = [[PlayerView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 300)];
_playerView.player = self.player;
return _playerView;
}
- (UIButton *)playButton {
if (_playButton) {
return _playButton;
}
_playButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[_playButton setTitle:@"播放" forState:UIControlStateNormal];
[_playButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_playButton addTarget:self action:@selector(playVideo) forControlEvents:UIControlEventTouchUpInside];
return _playButton;
}
- (UIButton *)pauseButton {
if (_pauseButton) {
return _pauseButton;
}
_pauseButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 50)];
[_pauseButton setTitle:@"暂停" forState:UIControlStateNormal];
[_pauseButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_pauseButton addTarget:self action:@selector(pauseVideo) forControlEvents:UIControlEventTouchUpInside];
return _pauseButton;
}
- (UIButton *)startPipButton {
if (_startPipButton) {
return _startPipButton;;
}
_startPipButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 200, 50)];
[_startPipButton setTitle:@"开启画中画功能" forState:UIControlStateNormal];
[_startPipButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[_startPipButton addTarget:self action:@selector(startPip) forControlEvents:UIControlEventTouchUpInside];
return _startPipButton;
}
//播放按钮的点击事件
- (void)playVideo {
NSLog(@"点击开始播放视频");
[self.playerView.player play];
}
//暂停按钮的点击事件
- (void)pauseVideo {
NSLog(@"暂停播放视频");
[self.playerView.player pause];
}
//开启画中画按钮的点击事件
- (void)startPip {
NSLog(@"点击开启画中画功能");
if (self.pipVC.pictureInPicturePossible) {
NSLog(@"允许开启画中画功能");
[self.pipVC startPictureInPicture];
} else {
NSLog(@"不允许开启画中画功能");
}
}
然后在viewDidLoad中实现界面的基本布局
[self.view addSubview:self.playerView];
self.playButton.frame = CGRectMake((self.view.bounds.size.width - 100) / 2, 320, 100, 50);
[self.view addSubview:self.playButton];
self.pauseButton.frame = CGRectMake((self.view.bounds.size.width - 100) / 2, 400, 100, 50);
[self.view addSubview:self.pauseButton];
self.startPipButton.frame = CGRectMake((self.view.bounds.size.width - 200) / 2, 460, 200, 50);
[self.view addSubview:self.startPipButton];
正常运行后,发现可以正常播放视频
接下来就可以添加画中画功能了
相应的控件及属性苹果开发者文档中都有提及,有兴趣的可以去阅读一下
实现画中画功能最重要的控件是AVPictureInPictureViewController是NSObject的子类(不是UIViewController的子类,所以我们不能将其添加到界面上)
定义相应的属性
@property (nonatomic, strong) AVPictureInPictureController *pipVC;
相应的懒加载
- (AVPictureInPictureController *)pipVC {
if (_pipVC) {
return _pipVC;
}
_pipVC = [[AVPictureInPictureController alloc] initWithPlayerLayer:self.playerView.playerLayer];
_pipVC.delegate = self;//需要遵守AVPictureInPictureControllerDelegate(协议是optional,不是必须要实现的,可以不实现)
return _pipVC;
}
实现相应的协议(协议是optional,不是必须要实现的,可以不实现)
- (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@"即将开启画中画功能");
}
- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@"已经开启画中画功能");
}
- (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@"即将停止画中画功能");
}
- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@"已经停止画中画功能");
}
- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController failedToStartPictureInPictureWithError:(NSError *)error {
NSLog(@"开启画中画功能失败,原因是%@",error);
}
同样的我们需要在开始时申请权限
在viewDidLoad中添加以下代码即可
if ([AVPictureInPictureController isPictureInPictureSupported]) {
NSLog(@"该设备支持画中画功能");
//开启画中画权限
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
if (error) {
NSLog(@"请求权限失败的原因为%@",error);
}
} else {
NSLog(@"该设备不支持画中画功能");
}
点击开启画中画按钮的方法实现
- (void)startPip {
NSLog(@"点击开启画中画功能");
//pictureInPicturePossible这个属性为YES才允许开启画中画,存在其他的软件正在开启画中画时,这个属性为NO
if (self.pipVC.pictureInPicturePossible) {
NSLog(@"允许开启画中画功能");
[self.pipVC startPictureInPicture];
} else {
NSLog(@"不允许开启画中画功能");
}
}
最终运行的效果图为:
总结
项目的demo地址为:
demo地址