iOS画中画悬浮提词功能(上)
目前很多App都通过iOS系统提供的画中画api将应用功能扩展到我们的手机桌面上了,比较出名的就是网易云的桌面歌词、b站的画中画播放、还有一些app的桌面倒计时以及悬浮提词功能。
正好接触提词器的功能,网上查询了很多资料都是付费的,在此记录一下实现方法
画中画功能本来是苹果针对iPad等大屏设备提供的多任务处理的一种实现方式,可以将视频窗口独立悬浮出来,满足用户观看视频时处理其他任务的需求。
但随着手机屏幕越做越大,该功能也逐渐下放至iOS平台,并且在iOS14以后的系统上开放给开发者使用。
话不多说,本篇先记录画中画的基础使用:
接入Pip
首先要做的是接入系统提供的画中画功能
在didFinishLaunchingWithOptions
中加入如下代码:
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
//1.判断是否支持画中画功能
if ([AVPictureInPictureController isPictureInPictureSupported]) {
//2.开启权限
@try {
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
[[AVAudioSession sharedInstance] setActive:YES error:&error];
} @catch (NSException *exception) {
NSLog(@"AVAudioSession发生错误");
}
}
配置画中画
前面说过,画中画本是为了将视频画面独立出来,因此我们需要一个视频播放器来调起pip。
我们可以使用系统的AVPlayer
也可以使用其他自定义播放器,这里使用AVPlayer
这里注意:playerLayer.frame 决定了画中画弹窗出现和消失时动画的位置和形状,根据需求调整
重点:初始视频的比例决定了画中画窗口的大小和比例,常见的有正方形、16\9、9\16、还有长条形,如果要控制窗口大小,在这里更换视频即可
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"full16_9" ofType:@"mp4"]];
AVAsset *asset = [AVAsset assetWithURL:url];
AVPlayerItem * item = [[AVPlayerItem alloc] initWithAsset:asset];
self.player = [AVPlayer playerWithPlayerItem:item];
self.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
self.playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];
self.playerLayer.videoGravity = AVLayerVideoGravityResize;
self.playerLayer.hidden = YES;
self.playerLayer.frame = CGRectMake(0, 0, kScreenWidth, 1);
[self.view.layer addSublayer:_playerLayer];
if ([AVPictureInPictureController isPictureInPictureSupported]) {
self.pipVC = [[AVPictureInPictureController alloc] initWithPlayerLayer:self.playerLayer];
if (@available(iOS 14.0, *)) {
self.pipVC.requiresLinearPlayback = YES;
} else {
}
self.pipVC.delegate = self;
}
这里为AVPictureInPictureController
添加了代理AVPictureInPictureControllerDelegate
,对画中画的生命周期暴露:
// 即将开启画中画
- (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@" 即将开启画中画");
}
// 已经开启画中画
- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
NSLog(@" 已经开启画中画");
}
// 开启画中画失败
- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController failedToStartPictureInPictureWithError:(NSError *)error {
NSLog(@" 开启画中画失败-%@", error);
}
// 即将关闭画中画
- (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
}
// 已经关闭画中画
- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
}
// 关闭画中画且恢复播放界面
- (void)pictureInPictureController:(AVPictureInPictureController *)pictureInPictureController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler {
}
开启画中画
开启画中画时,使用AVPIP提供的isPictureInPictureSupported
判断设备是否支持开启画中画。
这里还可以判断一下当前画中画是否已启动,通过startPictureInPicture
和stopPictureInPicture
来操作画中画视图的开启关闭。
@property (nonatomic, strong) AVPictureInPictureController *pipVC;
// 判断是否支持画中画功能
if ([AVPictureInPictureController isPictureInPictureSupported]) {
if (self.pipVC.isPictureInPictureActive) {
[self.pipVC stopPictureInPicture];
} else {
[self.pipVC startPictureInPicture];
}
} else {
// [CC_MBProgressHUD showWithStatus:@"当前系统版本过低,无法使用该功能,请升级系统版本后使用"];
}
到这里,播放视频的画中画窗口就可以正常展示了,下一篇记录在画中画上添加提词器视图。