swift - 将数据传递给 UICollectionViewCell 的正确方法
swift - Correct way to pass data to UICollectionViewCell
我正在尝试创建自己的图书应用程序,并使用 UICollectionView
列出所有图书。每个单元格的数据来自 .plist
文件,我正在使用自定义 flowLayout
(稍后进行一些更改)。
所以现在我在滚动时遇到了延迟和滞后。我想我在将数据传递给单元格或单元格初始化时犯了错误。
由 .xib
和自定义 class 创建的单元格,只是一些布局和 UI:
class BookCoverCell: UICollectionViewCell {
@IBOutlet weak var view1: UIView!
@IBOutlet weak var view2: UIView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var darkRedView: UIView!
@IBOutlet weak var lightRedView: UIView!
@IBOutlet weak var readButton: UIButton!
@IBOutlet weak var pageLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
clipsToBounds = true
self.backgroundColor = UIColor(white: 1, alpha: 0.0)
view1.layer.cornerRadius = 10
view2.layer.cornerRadius = 10
darkRedView.layer.cornerRadius = 10
lightRedView.layer.cornerRadius = 10
}
}
在 ViewController 的 class:
class MainVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate {
@IBOutlet weak var collectionContainerView: UIView!
@IBOutlet weak var collectionView: UICollectionView!
var books: Array<Book>? {
didSet {
collectionView.reloadData()
}
}
var flowLayout = UICollectionViewFlowLayout()
override func viewDidLayoutSubviews() {
flowLayout = ZoomAndSnapFlowLayout()
collectionView.collectionViewLayout = flowLayout
}
override func viewDidLoad() {
super.viewDidLoad()
collectionContainerView.backgroundColor = UIColor(white: 1, alpha: 0.0)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "BookCoverCell", bundle: nil), forCellWithReuseIdentifier: "BookCoverCell");
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
books = BookStore.sharedInstance.loadBooks(plist: "Books")
}
//MARK: UICollectionViewDelegate
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let books = books {
return books.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BookCoverCell", for: indexPath) as! BookCoverCell
let book = books![indexPath.row]
let cover = book.coverImage()!
let color = book.getDominantColor()
cell.view1.backgroundColor = color
cell.imageView.image = cover
cell.pageLabel.text = "Pages: 29"
cell.readButton.setTitle("Read", for: .normal)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let book = books?[indexPath.row]
print ("open")
}
}
我的布局现在看起来像:
class ZoomAndSnapFlowLayout: UICollectionViewFlowLayout {
var cellWidth = CGFloat()
var cellHeight = CGFloat()
var minLineSpacing = CGFloat()
override init() {
super.init()
self.scrollDirection = .horizontal
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
guard let collectionView = collectionView else { fatalError() }
cellHeight = collectionView.frame.height * 0.8
minLineSpacing = 200
cellWidth = cellHeight
itemSize = CGSize(width: cellWidth, height: cellHeight)
let verticalInsets = (collectionView.frame.height - collectionView.adjustedContentInset.top - collectionView.adjustedContentInset.bottom - itemSize.height) / 2
let horizontalInsets = (collectionView.frame.width - collectionView.adjustedContentInset.right - collectionView.adjustedContentInset.left - itemSize.width) / 2
sectionInset = UIEdgeInsets(top: verticalInsets, left: horizontalInsets, bottom: verticalInsets, right: horizontalInsets)
super.prepare()
}
}
所以我很确定我的代码中有一些错误,但找不到它们((任何建议都会对我有所帮助!
更新:
所以首先要感谢!
我已经更改了我的代码,用最小的图像替换了一个非常大的图像,并且现在可以将主色简单地转换为白色,事情已经变得更好了!
但是 第一次滚动开始时会有小的滞后或延迟,并且只有第一个和第二个单元格滚动到屏幕的左边缘。在那之后,所有单元格都在两个方向(左/右)滚动而没有滞后,甚至是前两个。
现在我的代码如下所示:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BookCoverCell", for: indexPath) as! BookCoverCell
let book = books![indexPath.row]
let cover = UIImage(named: "flag.png")
let color = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell.view1.backgroundColor = color
cell.imageView.image = cover
cell.pageLabel.text = "Pages: 29"
cell.readButton.setTitle("Read", for: .normal)
return cell
}
和更新#2
删除
flowLayout = ZoomAndSnapFlowLayout()
collectionView.collectionViewLayout = flowLayout
到 viewWillAppear()
也修复了这些小延迟!!万岁!)
阅读这篇关于时间分析和集合视图的文章:https://voxels.github.io/eliminating-collection-view-tearing-with-xcode-time-profiler-instrument
由于您的实现非常简单,可能出错的地方不多,但您可能遇到了与文章作者相同的问题——图像本身非常大,需要阅读并调整大小。
他们通过制作适当大小的图像版本解决了这个问题。
在你的情况下 getDominantColor
在大图像上也会变慢(我假设它读取像素以获得主色。你还应该考虑缓存这种颜色而不是每次都重新计算它(如果你还没有这样做)。
我正在尝试创建自己的图书应用程序,并使用 UICollectionView
列出所有图书。每个单元格的数据来自 .plist
文件,我正在使用自定义 flowLayout
(稍后进行一些更改)。
所以现在我在滚动时遇到了延迟和滞后。我想我在将数据传递给单元格或单元格初始化时犯了错误。
由 .xib
和自定义 class 创建的单元格,只是一些布局和 UI:
class BookCoverCell: UICollectionViewCell {
@IBOutlet weak var view1: UIView!
@IBOutlet weak var view2: UIView!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var darkRedView: UIView!
@IBOutlet weak var lightRedView: UIView!
@IBOutlet weak var readButton: UIButton!
@IBOutlet weak var pageLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
clipsToBounds = true
self.backgroundColor = UIColor(white: 1, alpha: 0.0)
view1.layer.cornerRadius = 10
view2.layer.cornerRadius = 10
darkRedView.layer.cornerRadius = 10
lightRedView.layer.cornerRadius = 10
}
}
在 ViewController 的 class:
class MainVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate {
@IBOutlet weak var collectionContainerView: UIView!
@IBOutlet weak var collectionView: UICollectionView!
var books: Array<Book>? {
didSet {
collectionView.reloadData()
}
}
var flowLayout = UICollectionViewFlowLayout()
override func viewDidLayoutSubviews() {
flowLayout = ZoomAndSnapFlowLayout()
collectionView.collectionViewLayout = flowLayout
}
override func viewDidLoad() {
super.viewDidLoad()
collectionContainerView.backgroundColor = UIColor(white: 1, alpha: 0.0)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UINib(nibName: "BookCoverCell", bundle: nil), forCellWithReuseIdentifier: "BookCoverCell");
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
books = BookStore.sharedInstance.loadBooks(plist: "Books")
}
//MARK: UICollectionViewDelegate
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let books = books {
return books.count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BookCoverCell", for: indexPath) as! BookCoverCell
let book = books![indexPath.row]
let cover = book.coverImage()!
let color = book.getDominantColor()
cell.view1.backgroundColor = color
cell.imageView.image = cover
cell.pageLabel.text = "Pages: 29"
cell.readButton.setTitle("Read", for: .normal)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let book = books?[indexPath.row]
print ("open")
}
}
我的布局现在看起来像:
class ZoomAndSnapFlowLayout: UICollectionViewFlowLayout {
var cellWidth = CGFloat()
var cellHeight = CGFloat()
var minLineSpacing = CGFloat()
override init() {
super.init()
self.scrollDirection = .horizontal
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepare() {
guard let collectionView = collectionView else { fatalError() }
cellHeight = collectionView.frame.height * 0.8
minLineSpacing = 200
cellWidth = cellHeight
itemSize = CGSize(width: cellWidth, height: cellHeight)
let verticalInsets = (collectionView.frame.height - collectionView.adjustedContentInset.top - collectionView.adjustedContentInset.bottom - itemSize.height) / 2
let horizontalInsets = (collectionView.frame.width - collectionView.adjustedContentInset.right - collectionView.adjustedContentInset.left - itemSize.width) / 2
sectionInset = UIEdgeInsets(top: verticalInsets, left: horizontalInsets, bottom: verticalInsets, right: horizontalInsets)
super.prepare()
}
}
所以我很确定我的代码中有一些错误,但找不到它们((任何建议都会对我有所帮助!
更新: 所以首先要感谢! 我已经更改了我的代码,用最小的图像替换了一个非常大的图像,并且现在可以将主色简单地转换为白色,事情已经变得更好了!
但是 第一次滚动开始时会有小的滞后或延迟,并且只有第一个和第二个单元格滚动到屏幕的左边缘。在那之后,所有单元格都在两个方向(左/右)滚动而没有滞后,甚至是前两个。
现在我的代码如下所示:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BookCoverCell", for: indexPath) as! BookCoverCell
let book = books![indexPath.row]
let cover = UIImage(named: "flag.png")
let color = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
cell.view1.backgroundColor = color
cell.imageView.image = cover
cell.pageLabel.text = "Pages: 29"
cell.readButton.setTitle("Read", for: .normal)
return cell
}
和更新#2 删除
flowLayout = ZoomAndSnapFlowLayout()
collectionView.collectionViewLayout = flowLayout
到 viewWillAppear()
也修复了这些小延迟!!万岁!)
阅读这篇关于时间分析和集合视图的文章:https://voxels.github.io/eliminating-collection-view-tearing-with-xcode-time-profiler-instrument
由于您的实现非常简单,可能出错的地方不多,但您可能遇到了与文章作者相同的问题——图像本身非常大,需要阅读并调整大小。
他们通过制作适当大小的图像版本解决了这个问题。
在你的情况下 getDominantColor
在大图像上也会变慢(我假设它读取像素以获得主色。你还应该考虑缓存这种颜色而不是每次都重新计算它(如果你还没有这样做)。