需求:
在TableViewCell中播放视频,根据设备横竖屏切换自动全屏或小窗口播放
错误的解决方案:
按照常规的做法,第一想法,就是监听旋转屏幕的方法,在旋转屏幕事件中对播放器进行操作。
实现如下,在当前UIViewController的根UIViewController(UINavigationController或者UITabBarController)进行旋转控制,代码如下
一、根UIViewController
1、声明变量
var orientationMask = UIInterfaceOrientationMask.portrait
var autorotate = false
var hiddenStatusBarIfNeed = false
2、声明控制函数
override var supportedInterfaceOrientations:UIInterfaceOrientationMask{
return orientationMask
}
override var prefersStatusBarHidden:Bool{
return hiddenStatusBarIfNeed
}
override var shouldAutorotate:Bool{
return autorotate
}
二、在播放视频的UIViewController中
1、播放时打开根UIViewController的旋转开关
open func shouldRotate() {
let landscapeController = navigationController as? LandscapeNavigatonController
if landscapeController == nil {
return
}
if videoPlayer.isPlaying {
landscapeController!.autorotate = true
landscapeController!.orientationMask = .allButUpsideDown
} else {
landscapeController!.autorotate = false
landscapeController!.orientationMask = .portrait
}
}
2、监听事件,对player进行操作(主要是调整player大小)
NotificationCenter.default.addObserver(self,
selector:#selector(onOrientationChanged),
name:NSNotification.Name.UIApplicationDidChangeStatusBarOrientation,
object:nil)
问题:
看似一切都没有问题,但是运行的时候,由于UIViewController旋转,导致UITableView会调用reloadData方法,而横竖屏幕的高度不一样,有可能导致会调用到UITableView的didEndDisplaying方法(这个方法中我们应该停止播放视频),所以这个方法不行
正确的解决方案:
我们只需要知道屏幕是否旋转,在旋转中对player进行操作即可,并不需要将整个UIViewController进行旋转,这样就不会调用到reloadData方法。实现方法如下:
1、关闭根UIViewController的旋转开关
2、监听设备旋转事件
3、对player进行旋转
weakself?.mediaPlayer.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
即可,关键代码:
func handleVideoFullScreen(deviceOrientation: UIDeviceOrientation) {
weak var weakself = self
let duration = 0.75
switch deviceOrientation {
case .portrait, .portraitUpsideDown:
playerControlView.showBackButton.isHidden = true
if let playerFrame = defaultPlayerFrame {
mediaPlayer.removeFromSuperview()
defaultPlayerSuperView?.addSubview(mediaPlayer)
UIView.animate(withDuration: duration) {
weakself?.mediaPlayer.transform = CGAffineTransform(rotationAngle: 0);
weakself?.mediaPlayer.frame = playerFrame
weakself?.defaultPlayerFrame = nil
}
UIApplication.shared.setStatusBarHidden(false, with: .fade)
UIApplication.shared.statusBarOrientation = .portrait
}
case .landscapeLeft:
playerControlView.showBackButton.isHidden = false
defaultPlayerSuperView = mediaPlayer.superview
defaultPlayerFrame = mediaPlayer.frame
// 获取相对坐标值
mediaPlayer.removeFromSuperview()
UIApplication.shared.setStatusBarHidden(false, with: .fade)
UIApplication.shared.statusBarOrientation = .landscapeRight
let frame = self.view.convert(mediaPlayer.frame, from: playingCell)
mediaPlayer.frame = frame
let keyWindow = UIApplication.shared.keyWindow
keyWindow?.addSubview(mediaPlayer)
UIView.animate(withDuration: duration) {
weakself?.mediaPlayer.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2))
weakself?.mediaPlayer.frame = CGRect(x: 0, y: 0, width: screenHeight, height: screenWidth)
}
case .landscapeRight:
playerControlView.showBackButton.isHidden = false
defaultPlayerSuperView = mediaPlayer.superview
defaultPlayerFrame = mediaPlayer.frame
mediaPlayer.removeFromSuperview()
UIApplication.shared.setStatusBarHidden(false, with: .fade)
UIApplication.shared.statusBarOrientation = .landscapeRight
let frame = self.view.convert(mediaPlayer.frame, from: playingCell)
mediaPlayer.frame = frame
let keyWindow = UIApplication.shared.keyWindow
keyWindow?.addSubview(mediaPlayer)
UIView.animate(withDuration: duration) {
weakself?.mediaPlayer.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2))
weakself?.mediaPlayer.frame = CGRect(x: 0, y: 0, width: screenHeight, height: screenWidth)
}
default:
break
}
}
其他相关的点
1、只有一个Player,当用户点击播放的时候,把Player加入到cell中播放,当全屏的时候,把Player加入到UIApplication.shared.keyWindow中旋转
2、全屏时,需要把player的在Cell的坐标转化为UIApplication.shared.keyWindow的坐标系
let frame = UIApplication.shared.keyWindow!.convert(mediaPlayer.frame, from: playingCell)
3、Cell被移除屏幕后停止播放,在didEndDisplaying方法中处理
网友评论