我在社区上探索了其他答案并尝试了这个 -
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
}
}
并且集合视图应该像这样实现:
实例化您的单元格
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 }
当 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() }
在滚动中处理播放状态
// 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() } } }