画中画功能探究

最近开始研究iOS14画中画功能的实现,最终分别通过使用AVPlayerViewController构建播放器和AVPlayerLayer构建播放器,分别实现相应的画中画的功能
实现的效果图为:


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(@"该设备不支持画中画功能");
    }

最终,我们得到的效果图为:


AVPlayerViewController实现画中画效果

AVPlayerLayer实现画中画的功能

首先,和原先一样,我们需要搭建一个能够播放视频的项目(在demo中文件名为secondViewController)

对于AVPlayerLayer是继承与CALayer,这个就是在view上添加一层layer用于播放视频。
(注意:这种方法播放视频没有系统提供控制栏,控制栏需要自己定义,下面我是定义了几个按钮)

对于AVPlayerLayer,我们打开苹果开发者文档,里面有给出其相应的封装例子,我们直接原样使用即可


开发者文档中的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(@"不允许开启画中画功能");
    }
}

最终运行的效果图为:


AVPlayerLayer实现画中画效果

总结

项目的demo地址为:
demo地址

你可能感兴趣的:(画中画功能探究)