我将如何动态添加适量的单元格并在其中显示视频

How would I dynamically add the right amount of cells and display videos in them

目前我有一个 swift 文件,其中我使用我创建的数据模型具有三个硬编码值,该数据模型包含标题、图像和 url(我只在此时此刻)。我了解如何更改每个单元格以显示其应在滚动视图中显示的相应图像:

import UIKit
import AVKit
import Firebase

struct CustomData {
var title: String
var image: UIImage
var url: String
}

var videoURL = ""
var array = [String]()

class HomeViewController: UIViewController {

var fileArray:Array<Any>?

fileprivate let data = [
    CustomData(title: "Test", image: #imageLiteral(resourceName: "ss-1"), url: "test.com"),
    CustomData(title: "Test2", image: #imageLiteral(resourceName: "done-button"), url: "test.com"),
    CustomData(title: "Test2", image: #imageLiteral(resourceName: "notificationIcon"), url: "test.com")
]

fileprivate let collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.translatesAutoresizingMaskIntoConstraints = false
    cv.register(CustomCell.self, forCellWithReuseIdentifier: "cell")
    return cv
}()

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(collectionView)
    collectionView.backgroundColor = .white
    collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 150).isActive = true
    collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
    collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16).isActive = true
    collectionView.heightAnchor.constraint(equalTo: collectionView.widthAnchor, multiplier: 0.5).isActive = true 

    collectionView.delegate = self
    collectionView.dataSource = self

    array = fileArray as! [String]
}
}

extension HomeViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDataSource{

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: collectionView.frame.width, height: collectionView.frame.width)
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return data.count
}

public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CustomCell
    cell.data = self.data[indexPath.row]
    return cell
}
}

class CustomCell: UICollectionViewCell{

var data: CustomData?{
    didSet{
        guard let data = data else { return }
        bg.image = data.image
    }
}

fileprivate let bg: UIImageView = {
    let iv = UIImageView()
    iv.image = #imageLiteral(resourceName: "splash_icon")
    iv.translatesAutoresizingMaskIntoConstraints = false
    iv.contentMode = .scaleAspectFill
    iv.clipsToBounds = true
    iv.layer.cornerRadius = 10
    return iv
}()

override init(frame: CGRect) {
    super.init(frame: frame)

    //        let player = AVPlayer(url: URL(string: videoURL)!)
    //        let playerLayer = AVPlayerLayer(player: player)
    //        playerLayer.frame = contentView.bounds
    //        contentView.layer.addSublayer(playerLayer)
    //        player.play()

    contentView.addSubview(bg)
    bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
    bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
    bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
    bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}

上面的代码成功地显示了我在 data 数组中指定的所有三个图像在各自单元格的滚动视图中。 我有一个数组,其中包含 10 个字符串,这些字符串在设备本地对不同的视频(所有大小相同)都是唯一的 url。我已通过更改此部分设法显示视频:

override init(frame: CGRect) {
super.init(frame: frame)

//        let player = AVPlayer(url: URL(string: videoURL)!)
//        let playerLayer = AVPlayerLayer(player: player)
//        playerLayer.frame = contentView.bounds
//        contentView.layer.addSublayer(playerLayer)
//        player.play()

contentView.addSubview(bg)
bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}

对此:

override init(frame: CGRect) {
super.init(frame: frame)

let player = AVPlayer(url: URL(string: videoURL)!)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = contentView.bounds
contentView.layer.addSublayer(playerLayer)
player.play()

//        contentView.addSubview(bg)
//        bg.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
//        bg.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
//        bg.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
//        bg.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}

但这显然在一个视频中进行了硬编码,并且同一视频将显示在滚动视图中的所有单元格上。那么我将如何做与我对 UIImageView 所做的相同的事情:

var data: CustomData?{
didSet{
    guard let data = data else { return }
    bg.image = data.image
}
}

fileprivate let bg: UIImageView = {
    let iv = UIImageView()
    iv.image = #imageLiteral(resourceName: "splash_icon")
    iv.translatesAutoresizingMaskIntoConstraints = false
    iv.contentMode = .scaleAspectFill
    iv.clipsToBounds = true
    iv.layer.cornerRadius = 10
    return iv
}()

但是使用 AVPlayer 或其他一些视频播放器使所有单元格动态显示不同的视频,我知道我必须更改数据模型并从数组中获取值等,我似乎无法找到一种与图像视图相同的方法。

谢谢,

内森

查看您的代码,由于您在 UIImageView

中设置 data.image 的代码块,您设法让图像显示为您想要的
var data: CustomData?{
    didSet{
        guard let data = data else { return }
        bg.image = data.image
    }
}

如果您想为每个单元格播放 data 中列出的视频,您需要使用 data.url 初始化 AVP 播放器。

不想把你的代码搞得一团糟,你可以试试这个:

 override init(frame: CGRect) {
        super.init(frame: frame)

      // only create the player if the data.url is present AND is a valid URL instead of just a bunch of normal text
      if let unwrappedURLString = data?.url, let url = URL(string: unwrappedURLString) {
        let player = AVPlayer(url: url)
        let playerLayer = AVPlayerLayer(player: player)
        playerLayer.frame = contentView.bounds
        contentView.layer.addSublayer(playerLayer)
        player.play()
      }
    } 

即使你想像你的 UIImageView 这样初始化它,在编译时仍然有很多问题需要解决和错误需要处理

fileprivate let player: AVPlayer = {
    let dataURL = data?.url ?? "random URL" // this will not compile because data is an instance variable which will not be available when this AVP player is initialized on memory load
    let url = URL(string: initialURL) // this line will still produce an optional URL so you need to also handle the unwrapping issue when you construct the URL here
    let player = AVPlayer(url: url)
    return player
  }()