You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现类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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:57:24