UITableView复用Cell导致YTPlayer控制失效及播放异常问题求助
解决信息流中YouTube视频与Spotify播放冲突的方案
嘿,这个问题我太熟了——Cell复用简直是信息流视频播放的噩梦!我来给你拆解几个靠谱的解决思路,完美解决你遇到的“找不到Cell停止视频”的问题:
核心思路:别跟踪Cell,跟踪播放状态和视频标识
Cell会被列表频繁复用、回收,存Cell引用大概率会失效。你应该把注意力放在播放状态的全局管理和视频的唯一标识上,而不是Cell本身。
1. 用全局状态记录当前播放的YouTube视频
维护几个全局(或者ViewModel层的)变量:
currentPlayingYouTubeID: String?:记录当前正在播放的视频IDisYouTubePlaying: Bool:标记是否有YouTube视频在播放
当用户点击YouTube视频Cell播放时,更新这两个变量:
// 在YouTubePostCell的播放按钮点击事件里 func playButtonTapped() { // 先停止之前可能在播放的视频(如果有的话) if let prevID = YourGlobalState.currentPlayingYouTubeID { // 这里可以结合下面的方法找到对应Cell停止,或者直接通过数据源处理 } self.ytPlayerView.playVideo() YourGlobalState.currentPlayingYouTubeID = self.videoID YourGlobalState.isYouTubePlaying = true }
2. 利用列表的可见性回调,自动停止移出屏幕的视频
借助UICollectionViewDelegate的didEndDisplayingCell方法——当Cell移出可视区域时,这个方法会被调用,此时Cell还没被复用,你可以安全地操作它的Player:
func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { guard let youtubeCell = cell as? YouTubePostCell, let currentID = YourGlobalState.currentPlayingYouTubeID, youtubeCell.videoID == currentID else { return } // 停止视频并更新全局状态 youtubeCell.ytPlayerView.stopVideo() YourGlobalState.currentPlayingYouTubeID = nil YourGlobalState.isYouTubePlaying = false }
3. 播放Spotify时,主动遍历可见Cell停止视频
当用户点击Spotify播放按钮时,不要依赖之前存的Cell,直接遍历当前列表的可见Cell,找到正在播放的YouTube视频并停止:
func spotifyPlayButtonTapped() { // 先处理正在播放的YouTube视频 if YourGlobalState.isYouTubePlaying { let visibleCells = yourCollectionView.visibleCells for cell in visibleCells { if let youtubeCell = cell as? YouTubePostCell, youtubeCell.videoID == YourGlobalState.currentPlayingYouTubeID, youtubeCell.ytPlayerView.isPlaying() { youtubeCell.ytPlayerView.stopVideo() break // 同一时间只应该有一个视频在播放 } } // 更新全局状态 YourGlobalState.currentPlayingYouTubeID = nil YourGlobalState.isYouTubePlaying = false } // 启动Spotify播放逻辑 // ... }
4. 监听YTPlayer状态,同步全局状态
给YTPlayerView添加状态监听,确保全局状态和实际播放状态完全同步,避免出现“全局标记在播放但实际视频已停止”的情况:
// 在YouTubePostCell的初始化或配置方法里 func configure(with videoID: String) { self.videoID = videoID ytPlayerView.delegate = self } // 实现YTPlayerViewDelegate方法 func playerView(_ playerView: YTPlayerView, didChangeToState state: YTPlayerState) { switch state { case .playing: YourGlobalState.currentPlayingYouTubeID = self.videoID YourGlobalState.isYouTubePlaying = true case .paused, .ended, .stopped: if YourGlobalState.currentPlayingYouTubeID == self.videoID { YourGlobalState.currentPlayingYouTubeID = nil YourGlobalState.isYouTubePlaying = false } default: break } }
额外注意事项
- 尽量把播放状态放到帖子模型里:给每个帖子模型加
isPlaying属性,列表刷新时能正确恢复播放状态 - 避免内存泄漏:在Cell的
prepareForReuse方法里,移除YTPlayer的监听,停止视频:override func prepareForReuse() { super.prepareForReuse() ytPlayerView.stopVideo() ytPlayerView.delegate = nil self.videoID = nil }
内容的提问来源于stack exchange,提问作者virajd
相关产品推荐
相关产品推荐

