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

UICollectionView单元格视频加载慢、滚动卡顿问题求助

信息流视频列表滚动卡顿优化方案

问题场景

  • 开发信息流页面,采用UIStackView嵌套UICollectionView布局,不同分类下包含多个视频
  • 滚动UICollectionView时,视频加载耗时、滚动出现明显卡顿
  • 当前单元格播放视频的核心代码:
self.videoPreview.layer.sublayers?.forEach {
    if $0 is AVPlayerLayer {
        $0.removeFromSuperlayer()
    }
}

self.player = AVPlayer(url: self.templateURL)
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.videoPreview.bounds
self.player!.isMuted = true
self.videoPreview.layer.addSublayer(playerLayer)
self.player!.play()
self.layoutSubviews()
self.videoPreview.layoutIfNeeded()

优化方案

1. 复用播放器与播放器层,避免重复创建

每次Cell复用都销毁重建AVPlayer和AVPlayerLayer是卡顿的核心原因,改用复用池模式减少资源开销:

// 在Cell所属的ViewController或全局单例中维护复用池
private var playerCache: [URL: AVPlayer] = [:]
private var playerLayerPool: [AVPlayerLayer] = []

// 修改Cell内的配置逻辑
func setupVideo(with url: URL) {
    // 回收旧的PlayerLayer到池子里
    self.videoPreview.layer.sublayers?.forEach {
        if let layer = $0 as? AVPlayerLayer {
            layer.removeFromSuperlayer()
            playerLayerPool.append(layer)
        }
    }
    
    // 复用已有的播放器,没有则创建
    self.player = playerCache[url] ?? AVPlayer(url: url)
    playerCache[url] = self.player
    
    // 复用PlayerLayer,没有则创建
    let playerLayer = playerLayerPool.popLast() ?? AVPlayerLayer(player: self.player)
    playerLayer.player = self.player
    playerLayer.frame = self.videoPreview.bounds
    self.player?.isMuted = true
    self.videoPreview.layer.addSublayer(playerLayer)
    
    self.player?.play()
    // 移除不必要的手动布局调用,Cell的布局由系统自动处理
}

// Cell复用前回收资源
override func prepareForReuse() {
    super.prepareForReuse()
    self.player?.pause()
    self.videoPreview.layer.sublayers?.forEach {
        if let layer = $0 as? AVPlayerLayer {
            layer.removeFromSuperlayer()
            playerLayerPool.append(layer)
        }
    }
    self.player = nil
}

2. 按需加载与播放,减少后台资源消耗

  • 只对当前可见Cell及上下各1-2个预加载,避免一次性加载所有视频
  • 利用CollectionView的生命周期方法控制播放/暂停:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    guard let videoCell = cell as? VideoCell else { return }
    videoCell.player?.play()
}

func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    guard let videoCell = cell as? VideoCell else { return }
    videoCell.player?.pause()
}

3. 优化布局与渲染性能

  • 替换UIStackView嵌套CollectionView的结构,直接用CollectionView的分区实现分类,减少嵌套层级带来的布局计算开销
  • 给视频容器开启光栅化,减少实时渲染压力:
self.videoPreview.layer.shouldRasterize = true
self.videoPreview.layer.rasterizationScale = UIScreen.main.scale

4. 视频资源层面优化

  • 使用HLS自适应码流,根据用户网络情况自动切换清晰度
  • 提前加载视频封面图,在视频未加载完成时显示封面,提升感知体验

内容的提问来源于stack exchange,提问作者Nabeel ali

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 03:55:25