如何实现类YouTube的UIView全屏?全屏后无法覆盖整屏疑受XLPagerTab影响
解决VideoPlayer无法全屏的问题
你的问题核心是VideoPlayer被XLPagerTab的父视图(通常是UIScrollView)裁剪了——因为UIScrollView默认开启clipsToBounds = true,视图超出其边界的部分会被隐藏,直接修改frame和transform无法突破这个限制。正确的做法是将VideoPlayer临时移到window层级,脱离原父视图的约束,就能实现全屏覆盖。
修改后的实现代码
首先在VideoPlayer类中添加属性保存原始状态:
class VideoPlayer: UIView { var isExpanded = false private var originalSuperview: UIView? private var originalFrame: CGRect = .zero private var smallScreenCenter: CGPoint? // 保留你原有的这个属性 // 你的AVPlayerLayer、控制组件等属性...
然后重写fullScreenTapped方法:
func fullScreenTapped() { if !isExpanded { // 1. 保存当前父视图和位置,用于退出全屏时恢复 originalSuperview = superview originalFrame = frame removeFromSuperview() // 2. 获取当前应用的主window guard let window = UIApplication.shared.keyWindow ?? UIApplication.shared.windows.first else { return } // 3. 将VideoPlayer添加到window层级 window.addSubview(self) frame = window.bounds UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { // 旋转90度并调整到全屏尺寸 self.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 2)) self.frame = CGRect(x: 0, y: 0, width: window.bounds.height, height: window.bounds.width) self.center = window.center // 更新子视图布局 self.layoutIfNeeded() // 隐藏状态栏 if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { scene.statusBarManager?.isStatusBarHidden = true } else { UIApplication.shared.isStatusBarHidden = true } }, completion: nil) } else { UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: { // 恢复原始状态 self.transform = CGAffineTransform.identity self.frame = self.originalFrame self.center = self.smallScreenCenter ?? self.originalSuperview?.center ?? .zero // 显示状态栏 if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { scene.statusBarManager?.isStatusBarHidden = false } else { UIApplication.shared.isStatusBarHidden = false } self.layoutIfNeeded() }, completion: { _ in // 动画结束后移回原父视图 guard let originalSuperview = self.originalSuperview else { return } self.removeFromSuperview() originalSuperview.addSubview(self) }) } isExpanded = !isExpanded }
最后确保AVPlayerLayer跟随视图尺寸变化:
override func layoutSubviews() { super.layoutSubviews() // 更新AVPlayerLayer的frame if let playerLayer = layer.sublayers?.first(where: { $0 is AVPlayerLayer }) as? AVPlayerLayer { playerLayer.frame = bounds } // 你的其他子视图布局逻辑... }
关键优化点说明
- 脱离父视图约束:将VideoPlayer移到window层级,彻底摆脱XLPagerTab的scrollView裁剪限制。
- 避免手动调用layoutSubviews:用
layoutIfNeeded触发布局更新,符合UIKit的布局规范。 - 状态栏适配:针对iOS 13+和旧版本分别处理状态栏隐藏逻辑。
- 状态恢复:保存原始父视图和位置,确保退出全屏时能准确回到初始状态。
内容的提问来源于stack exchange,提问作者ARES
相关产品推荐
相关产品推荐

