英文:
How would I dynamically add the right amount of cells and display videos in them
问题
下面是您要翻译的代码部分:
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")
}
}
请注意,代码中有一部分注释,用于显示视频。您需要根据您的需求来取消注释并更改视频的URL。
英文:
At the moment I have a swift file where I have three hardcoded values using a datamodel I also created that takes a title, image and url (I'm only showing the image at the moment). I understand how to change each cell to show its respective image that it should show in the scrollview:
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")
}
}
The code above successfully shows all the three images I specified in the data
array in the scroll view in their respective cell.
I have an array that holds 10 strings which are all unique urls locally on the device to different videos (all of the same size). I have managed to display a video by changing this part:
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
}
to this:
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
}
but that obviously hardcodes in one video and that same video will be shown on all of the cells in the scroll view. So how would I do the same as I did with the 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
}()
but with AVPlayer or some other video player to make all the cells dynamically show the different videos, I know I'll have to change the datamodel and get values from the array etc, I just can't seem to find a way to do the same as I did with the image view.
Thanks,
Nathan
答案1
得分: 1
因为你在设置data.image
到你的UIImageView
的代码块中,所以在查看你的代码时,你成功地让图像显示在你想要的位置。
如果你想在每个单元格中播放列出的视频,你需要使用data.url
来初始化AVP播放器。
为了不要太乱你的代码,你可以尝试这样做:
override init(frame: CGRect) {
super.init(frame: frame)
// 仅在data.url存在且是有效的URL而不仅仅是一堆普通文本时才创建播放器
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" // 这将无法编译,因为data是一个实例变量,在初始化内存加载时不可用
let url = URL(string: initialURL) // 这一行仍然会产生一个可选的URL,所以你需要在这里构建URL时处理解包问题
let player = AVPlayer(url: url)
return player
}()
英文:
Taking a look at your codes, you managed to get the images showing as you wanted because of this codeblock where you are setting data.image
into your UIImageView
var data: CustomData?{
didSet{
guard let data = data else { return }
bg.image = data.image
}
}
If you want to play the videos listed in your data
for each cell, you will need to initialize the AVP player with data.url
.
Not wanting to mess up too much of your code, what you can try is this:
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()
}
}
even if you wanted to initialize this like your UIImageView like this, there are still a lot of issues to address and errors to handle when compiling
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
}()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论