如何让Video Selection Controller中选中的视频可播放?
解决视频选择器无法播放视频的问题
我看了你的代码,现在的问题是你只获取了视频的首帧图片并显示,没有实现视频播放的逻辑。要达到类似Instagram的视频选择器效果,我们需要改造你的SelectVideoHeader,加入AVPlayer来处理视频播放,同时添加播放控制逻辑。下面是具体的解决方案:
1. 改造SelectVideoHeader,添加视频播放组件
首先我们需要给头部视图添加AVPlayer、AVPlayerLayer以及可选的播放按钮,用来控制视频播放:
import UIKit import AVFoundation class SelectVideoHeader: UICollectionReusableView { // 视频播放器相关 private var videoPlayer: AVPlayer? private var videoPlayerLayer: AVPlayerLayer? // 首帧图片占位 let videoSelectView: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFill iv.clipsToBounds = true return iv }() // 播放按钮(可选,如果你需要用户点击播放) let playButton: UIButton = { let button = UIButton(type: .system) let playImage = UIImage(systemName: "play.circle.fill")?.withRenderingMode(.alwaysTemplate) button.setImage(playImage, for: .normal) button.tintColor = .white button.isHidden = true button.addTarget(self, action: #selector(togglePlay), for: .touchUpInside) button.setDimensions(width: 80, height: 80) return button }() override init(frame: CGRect) { super.init(frame: frame) setupSubviews() } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupSubviews() { addSubview(videoSelectView) videoSelectView.fillSuperview() addSubview(playButton) playButton.center(inView: self) } // 配置视频播放器,传入选中的PHAsset func configureVideo(with asset: PHAsset) { // 先移除旧的播放器层,避免重复添加 videoPlayerLayer?.removeFromSuperlayer() // 请求视频资源(支持iCloud视频) let videoOptions = PHVideoRequestOptions() videoOptions.isNetworkAccessAllowed = true PHImageManager.default().requestAVAsset(forVideo: asset, options: videoOptions) { [weak self] (avAsset, _, _) in guard let self = self, let urlAsset = avAsset as? AVURLAsset else { return } self.videoPlayer = AVPlayer(url: urlAsset.url) self.videoPlayerLayer = AVPlayerLayer(player: self.videoPlayer) self.videoPlayerLayer?.frame = self.bounds self.videoPlayerLayer?.videoGravity = .resizeAspectFill self.layer.addSublayer(self.videoPlayerLayer!) // 两种模式可选: // 1. 自动播放(类似Instagram) // self.videoPlayer?.play() // self.playButton.isHidden = true // 2. 显示播放按钮,等待用户点击 self.playButton.isHidden = false // 监听视频播放结束,重置播放状态 NotificationCenter.default.addObserver( self, selector: #selector(self.handleVideoEnd), name: .AVPlayerItemDidPlayToEndTime, object: self.videoPlayer?.currentItem ) } } // 切换播放/暂停状态 @objc private func togglePlay() { guard let player = videoPlayer else { return } if player.timeControlStatus == .playing { player.pause() playButton.isHidden = false } else { player.play() playButton.isHidden = true } } // 视频播放结束后重置到开头 @objc private func handleVideoEnd() { videoPlayer?.seek(to: .zero) playButton.isHidden = false } // 暂停视频(页面消失时调用) func pauseVideo() { videoPlayer?.pause() playButton.isHidden = false } // 移除通知监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
2. 更新SelectVideoController的头部视图逻辑
修改viewForSupplementaryElementOfKind方法,现在我们不仅要设置首帧图片,还要配置视频播放器:
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath) as! SelectVideoHeader self.header = header if let selectedImage = self.selectedImage { if let index = self.images.firstIndex(of: selectedImage) { let selectedAsset = self.assets[index] // 先加载首帧作为占位图 let videoManager = PHImageManager.default() let targetSize = CGSize(width: 600, height: 600) videoManager.requestImage(for: selectedAsset, targetSize: targetSize, contentMode: .default, options: nil) { (image, _) in header.videoSelectView.image = image } // 配置视频播放 header.configureVideo(with: selectedAsset) } } return header }
3. 优化选中视频和页面生命周期的逻辑
在选中新视频时,先暂停当前视频;页面消失时也要暂停视频,避免后台播放:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 先暂停当前播放的视频 header?.pauseVideo() self.selectedImage = images[indexPath.row] self.collectionView?.reloadData() let headerIndexPath = IndexPath(item: 0, section: 0) collectionView.scrollToItem(at: headerIndexPath, at: .bottom, animated: true) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // 页面消失时暂停视频 header?.pauseVideo() }
关键说明
- 两种播放模式:你可以选择自动播放(注释掉播放按钮显示代码,打开自动播放逻辑),或者显示播放按钮让用户手动触发播放
- iCloud视频支持:设置
PHVideoRequestOptions的isNetworkAccessAllowed为true,可以访问用户存储在iCloud上的视频 - 内存管理:使用
weak self避免循环引用,在deinit中移除通知监听,防止内存泄漏 - 权限配置:确保你在
Info.plist中添加了NSPhotoLibraryUsageDescription,申请相册访问权限
内容的提问来源于stack exchange,提问作者user9611921
相关产品推荐
相关产品推荐

