swift4.0实现视频播放、屏幕旋转、倍速播放、手势调节及锁屏面

2020-01-09 00:09:32王旭

在对播放器status属性监听中加入了控制面板信息,是由MPNowPlayingInfoCenter来实现的,通过改变nowPlayingInfo里面对应的信息来更新面板信息,里面有好多属性,比如MPMediaItemPropertyTitle设置音频标题,MPMediaItemPropertyArtist作者、MPNowPlayingInfoPropertyElapsedPlaybackTime当前播放过的时间、MPMediaItemPropertyPlaybackDuration播放总时间等等。刚开始做的时候因为锁屏要更新时间,而nowPlayingInfo又是一个字典类型的再加上需要更新界面布局的时间和进度条,直接将播放器时间强制转换成 string 类型,所以将这一部分放到了时间观察里面,因为时间观察会一直进行所以锁屏界面信息也会一直更新,这样带来一个问题就是锁屏界面的图片如果是网络图片,每1秒就要请求一下图片而且要不断的更新这样带来的结果可想而知。后来才知道,将MPNowPlayingInfoPropertyElapsedPlaybackTime属性设置成self.player!.currentTime()播放器当前时间就会自动更新控制面板信息,调用的地方也很关键,必须放在播放器已经播放的监听里面。

配置远程控制显示的信息

响应远程控制是由MPRemoteCommandCenter来实现的,里面有很多属性,比如:playCommand播放响应事件、pauseCommand 暂停响应事件、nextTrackCommand下一曲响应事件、likeCommand喜欢按钮,类似网易云音乐的那个锁屏,如果设置了likeCommand则dislikeCommand是上一首响应事件、previousTrackCommand上一首,外部拖动进度条是changePlaybackPositionCommand,系统有一个专门的方法来出来远程拖动进度条响应事件:


open func addTarget(handler: @escaping (MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus) -> Any

大概控制面板能用到的这些信息差不多也就这么多,如果想了解更多的可以看一下文档或者查阅资料。

屏幕旋转问题

一个视频播放实现起来并不困难,只要处理好player与platitem就行了。最难的就是,如果手机屏幕旋转,怎么能让视频跟着屏幕自适应呢,我在工程里面通过UIDevice变化添加的是屏幕旋转监听:


/**
* 监听设备旋转通知
*/
private func listeningRotating() {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, selector: #selector(onDeviceOrientationChange), name:NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}

如果用户把屏幕旋转关掉,就是控制中心那个开关,用户旋转屏幕,怎么能让画面跟着跑呢,我百度的很多资料,试了也很多方法,但是都不理想,用的还是OC的代码,因为swift里面移除了NSInvocation属性,用的依然是OC的屏幕强制旋转,只能使用桥接文件:


//这个方法是在网上找的
+ (void)interfaceOrientation:(UIInterfaceOrientation)orientation{
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
SEL selector = NSSelectorFromString(@"setOrientation:");
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
[invocation setSelector:selector];
[invocation setTarget:[UIDevice currentDevice]];
int val = orientation;
// 从2开始是因为0 1 两个参数已经被selector和target占用
[invocation setArgument:&val atIndex:2];
[invocation invoke];
 }
}