在UICollectionViewCell中播放视频.视频播放正常,但在收藏视图上具有滚动性能



我在社区上探索了其他答案并尝试了这个 -

    player = AVPlayer()
    player.volume = 0.0
    player.actionAtItemEnd = AVPlayerActionAtItemEnd.None
    addPlayerLayer()
    let asset = AVAsset.init(URL: videoURL)
    asset.loadValuesAsynchronouslyForKeys(["duration", "playable"]) {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                let item = AVPlayerItem.init(asset: asset)
                self.player.replaceCurrentItemWithPlayerItem(item)
                self.player.play()
        })
    }

但是每当网络速度较慢时,滚动collectionView时就会出现明显的滞后/打嗝。我做错了什么吗?请帮助

请查看Facebook的AsyncDisplayKit(Facebook和Instagram提要背后的引擎),您可以使用其AVideoNode在后台线程上渲染大部分视频。

或:

player = AVPlayer()
player.volume = 0.0
player.actionAtItemEnd = AVPlayerActionAtItemEnd.None
addPlayerLayer()
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {}
    let asset = AVAsset.init(URL: videoURL)
    asset.loadValuesAsynchronouslyForKeys(["duration", "playable"]) {
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
                let item = AVPlayerItem.init(asset: asset)
                self.player.replaceCurrentItemWithPlayerItem(item)
                self.player.play()
        })
    }
})

这是一个示例,如何在集合视图中播放视频视图单元格而不会滚动延迟。

首先,我们必须准备好在不添加项目或资产的情况下在单元格的 init 方法中播放视频所需的一切,然后我们可以在异步分配视频 url 或路径时创建我们的资产或项目。

第二件重要的事情是将视频大小调整为单元格大小乘以 2(例如,我的单元格大小为 (w:50, h:50),我将视频大小调整为 (w:100, h:100) 以获得良好的质量)。

在此示例中,我将使用 AVPlayerLooper 自动循环播放视频,以便您可以根据需要使用 AVPlayer 进行更改。

示例集合视图单元格类:

import UIKit
import AVKit
class ExampleCell: UICollectionViewCell {
    public var isPlaying: Bool = false
    public var videolink: URL? = nil {
        didSet {
            guard let link = videolink, oldValue != link else { return }
            loadVideoUsingURL(link)
        }
    }
    private var queuePlayer = AVQueuePlayer()
    private var playerLayer = AVPlayerLayer()
    private var looperPlayer: AVPlayerLooper?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        commonInit()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        
        commonInit()
    }
    
    private func commonInit() {
        
        queuePlayer.volume = 0.0
        queuePlayer.actionAtItemEnd = .none
        
        playerLayer.videoGravity = .resizeAspect
        playerLayer.name = "videoLoopLayer"
        playerLayer.cornerRadius = 5.0
        playerLayer.masksToBounds = true
        contentView.layer.addSublayer(playerLayer)
        playerLayer.player = queuePlayer
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        
        /// Resize video layer based on new frame
        playerLayer.frame = CGRect(origin: .zero, size: CGSize(width: frame.width, height: frame.width))
    }
    
    private func loadVideoUsingURL(_ url: URL) {
        /// Load asset in background thread to avoid lagging
        DispatchQueue.global(qos: .background).async {
            let asset = AVURLAsset(url: url)
            /// Load needed values asynchronously
            asset.loadValuesAsynchronously(forKeys: ["duration", "playable"]) {
                /// UI actions should executed on the main thread
                DispatchQueue.main.async { [weak self] in
                    guard let `self` = self else { return }
                    let item = AVPlayerItem(asset: asset)
                    if self.queuePlayer.currentItem != item {
                        self.queuePlayer.replaceCurrentItem(with: item)
                        self.looperPlayer = AVPlayerLooper(player: self.queuePlayer, templateItem: item)
                    }
                }
            }
        }
    }
    
    public func startPlaying() {
        queuePlayer.play()
        isPlaying = true
    }
    
    public func stopPlaying() {
        queuePlayer.pause()
        isPlaying = false
    }
}

并且集合视图应该像这样实现:

  1. 实例化您的单元格

     func collectionView(_ collectionView: UICollectionView,
                        cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: ExampleCell.self),
                                                            for: indexPath) as? ExampleCell else {
            return UICollectionViewCell()
        }
        cell.videolink = videoFileURL
        return cell
    }
    
  2. 当 collectionView 将显示单元格时开始播放视频,并在它结束时停止播放以显示

    func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        guard let videoCell = cell as? ExampleCell else { return }
        videoCell.startPlaying()
    }
    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
        guard let videoCell = cell as? ExampleCell else { return }
        videoCell.stopPlaying()
    }
    
  3. 在滚动中处理播放状态

    // TODO: write logic to stop the video before it begins scrolling
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
       let cells = collectionView.visibleCells.compactMap({ $0 as? ExampleCell })
       cells.forEach { videoCell in
           if videoCell.isPlaying {
               videoCell.stopPlaying()
           }
       }
    }
    // TODO: write logic to start the video after it ends scrolling
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
       guard !decelerate else { return }
       let cells = collectionView.visibleCells.compactMap({ $0 as? ExampleCell })
       cells.forEach  { videoCell in
           if !videoCell.isPlaying && canPlayVideos {
               videoCell.startPlaying()
           }
       }
    }
    // TODO: write logic to start the video after it ends scrolling (programmatically)
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let cells = collectionView.visibleCells.compactMap({ $0 as? ExampleCell })
        cells.forEach { videoCell in
           // TODO: write logic to start the video after it ends scrolling
           if !videoCell.isPlaying && canPlayVideos {
               videoCell.startPlaying()
           }
       }
    }
    

最新更新