当 UICollectionViewCell 不在视图中时尝试暂停视频

Trying to pause video when the UICollectionViewCell is out of view

我正在使用从 Firebase 加载的 URL 填充集合视图。但是当我退出视图或向上滚动集合视图时,我无法让视频暂停。当我使用导航控制器返回时,我仍然可以听到后台播放的视频。然后当我再次进入视图时,视频开始播放,但第一个没有播放完。

这是我的视图控制器。有小费吗?谢谢你!我对 Swift 还是个新手,所以请原谅我的无知。

import UIKit
import AVKit
import AVFoundation
import Firebase
import FirebaseDatabase
import SDWebImage

class ComedyViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {

    var avPlayer = AVPlayer()
    var avPlayerLayer = AVPlayerLayer()

    @IBOutlet weak var comedyCollectionView: UICollectionView!

    var comedyVideoArray = [ComedyModel]()

    var comedyDBRef: DatabaseReference! {
        return Database.database().reference().child("comedy")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        loadComedyDB()
    }


    func loadComedyDB() {
        comedyDBRef.observe(DataEventType.value, with: { (snapshot) in

            if snapshot.childrenCount > 0 {
                self.comedyVideoArray.removeAll()

                for comedyData in snapshot.children.allObjects as! [DataSnapshot] {
                    let comedyObject = comedyData.value as? [String: AnyObject]
                    let comedyPostTitle = comedyObject?["title"]
                    let comedyPostDescription = comedyObject?["description"]
                    let comedyArticleLink = comedyObject?["link"]
                    let comedyVideoUrl = comedyObject?["url"]
                    let allComedyData = ComedyModel(title: comedyPostTitle as! String?, description: comedyPostDescription as! String?, link: comedyArticleLink as! String?, url: comedyVideoUrl as! String?)

                    self.comedyVideoArray.append(allComedyData)

                    self.comedyCollectionView.reloadData()
                }
            }
        })
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print(comedyVideoArray.count)
        return comedyVideoArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cellB = comedyCollectionView.dequeueReusableCell(withReuseIdentifier: "comedyCell", for: indexPath) as! ComedyCollectionViewCell
        let data = comedyVideoArray[indexPath.row]
        let item = AVPlayerItem(url: URL(string: data.url!)!)

        self.avPlayer = AVPlayer(playerItem: item)
        self.avPlayer.actionAtItemEnd = .none

        self.avPlayerLayer = AVPlayerLayer(player: self.avPlayer)
        self.avPlayerLayer.videoGravity = .resizeAspectFill
        self.avPlayerLayer.frame = CGRect(x: 0, y: 0, width: cellB.frame.size.width, height: cellB.frame.size.height / 2)

        cellB.videoView.layer.addSublayer(self.avPlayerLayer)

        self.avPlayer.play()
        //cellB.videoView.sd_setImage(with: URL(string: data.link!), placeholderImage: UIImage(named: "1"))

        return cellB
    }

    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {

        if collectionView == self.comedyCollectionView {
            self.avPlayer.pause()
        }
    }
}

有几个问题:

  1. UICollectionView 在显示新单元格之前调用 cellForItemAt,这意味着旧单元格仍然可见。现在,当您使新单元格出列时,您正在将指针 avPlayer 更改为 AVPlayer 的新实例,这样当您暂停视频时,您实际上是在新单元格上调用 pause()视频。旧的继续播放(在当时仍然可见的单元格中)。

  2. 每次 UICollectionView 调用 cellForItemAt 时,您都会将 AVPlayer 的实例添加到单元格中。但是 UICollectionView 尝试重用那些不再可见的单元格,因此您最终会在每个单元格中得到很多 AVPlayer。为避免这种情况,您应该查看如何在单元格上使用 prepareForReuse 方法。我还建议您在单元格本身中创建 AVPlayer(通过子类化 UICollectionViewCell),然后在 cellForItemAt 方法中设置它的 playerItem。这样你就可以在你的 didEndDisplaying 方法中暂停当前播放的视频,就像这样(只是一个例子):

    func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
      if let comedyCell = cell as? ComedyCollectionViewCell {
        comedyCell.avPlayer.pause()
      } 
    }