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

Adr*_*rro 1 xcode avplayer uicollectionview uicollectionviewcell swift

我正在使用从 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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*yev 9

有几个问题:

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

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

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