iOS 使用AVPictureInPictureController画中画实现自定义歌词

背景

产品要求实现类似QQ音乐和网易音乐歌词的画中画悬浮窗显示。网上搜罗了一下相关资料,都没有完整的方案,于是自己进行了相关的调研。

效果

1009.gif

实现步骤

1. 项目开启画中画后台模式

image.png

2. 配置画中画相关参数和组件
  • 首先我们需要知道,苹果的画中画功能本身就是给播放视频用的,将它用来做歌词显示,使用起来限制会较多,比如无法直接自定义窗口大小,有播放按钮遮挡等问题。但是可以通过取巧的方式实现。实现方式是在画中画最底层播放一个占位视频,顶层实现我们需要显示的交互。窗口大小由底层视频的尺寸比例决定(间接实现宽高调整)。
  • 播放视频的尺寸有一定的要求,当视频宽度较小时或者当高宽比较大时,双击画中画会自动缩小/放大,而我们显示歌词时往往不希望缩放;自己多次验证过,当视频宽度2000,高度小于700较为合适。
  • controlsStyle设置为1,屏蔽画中画的播放按钮。这个是私有属性。
  • canStartPictureInPictureAutomaticallyFromInline = YES,表示后台时自动打开画中画。
  • 后台切回前台时,画中画缩放的位置由playerLayer.frame决定。
- (void)preparePicInPicOnView:(UIView *)view {
    /// 设置播放模式
    NSError *error = nil
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]
    [[AVAudioSession sharedInstance] setActive:YES error:&error]
    /// 设置播放的视频
    NSURL *url = [[NSBundle mainBundle] URLForResource:@"0920-2000400" withExtension:@"mp4"]
    AVPlayerItem * item = [[AVPlayerItem alloc] initWithAsset:[AVAsset assetWithURL:url]]
    AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:item]
    
    AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:player]
    playerLayer.frame = self.screenView.bounds
    playerLayer.backgroundColor = [UIColor blackColor].CGColor
    playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    
    [view.layer insertSublayer:playerLayer atIndex:0]
    
    /// 画中画功能
    self.pipController = [[AVPictureInPictureController alloc] initWithPlayerLayer:playerLayer]
    self.pipController.requiresLinearPlayback = YES
    [self.pipController setValue:@1 forKey:@"controlsStyle"]
    self.pipController.delegate = self
    self.pipController.canStartPictureInPictureAutomaticallyFromInline = YES
    [player play]
    
    /// 播放结束自动循环播放
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil]
    /// 监听获取画中画Window
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidBecomeVisible:) name:UIWindowDidBecomeVisibleNotification object:nil]
}
3. 获取画中画顶层window

监听UIWindowDidBecomeVisibleNotification通知,获取画中画最顶层的Window,不要在pictureInPictureControllerWillStartPictureInPicture:代理中获取,很多时候会有两个window,导致获取的Window不正确!

- (void)windowDidBecomeVisible:(NSNotification *)notification {
    id object = notification.object;
    if ([object isKindOfClass:NSClassFromString(@"PGHostedWindow")]) {
        self.firstWindow = notification.object;
        NSLog(@"更新了Windows");
        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UIWindowDidBecomeVisibleNotification
                                                      object:nil];
        
    }
}
4. 监听代理

启动画中画时,将显示的容器放到画中画的Window中。

- (void)pictureInPictureControllerWillStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
    NSLog(@"即将开启画中画功能");
    if (self.firstWindow) {
        [self.firstWindow addSubview:self.picInPicView];
        [self.picInPicView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.edges.mas_equalTo(self.firstWindow);
        }];
    }
}

- (void)pictureInPictureControllerDidStartPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
    NSLog(@"已经开启画中画功能");
}

- (void)pictureInPictureControllerWillStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
    NSLog(@"即将停止画中画功能");
}

- (void)pictureInPictureControllerDidStopPictureInPicture:(AVPictureInPictureController *)pictureInPictureController {
    NSLog(@"已经停止画中画功能");
}

总结

此次调研,主要是解决的问题点是:

  1. 画中画的尺寸如何自定义:苹果没有接口直接调整大小,但可以通过播放的视频尺寸来改变大小,即当你画中画播放2000*500的视频时,尺寸就和歌词显示尺寸差不多。
  2. 画中画窗口如何禁用双击缩放手势:当视频尺寸宽度较大,且高度较小时,系统会自动屏蔽双击缩放手势。较合适的尺寸为宽度2000,高度小于700。
  3. 画中画中如何屏蔽原生播放按钮:controlsStyle属性设置为1。
  4. 切后台如何自动唤起画中画:canStartPictureInPictureAutomaticallyFromInline属性设置为YES,并将视频一直循环播放,切后台就会自动唤起画中画。另外需要注意,视频播放的layer的frame一定要在可视区域,当不在可是区域时,也无法唤起画中画。

demo链接:github.com/yuchern/Pic…

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=21207,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?