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
相关产品推荐
相关产品推荐

