我正在制作一个应用程序,其中集合的单个单元格占据整个屏幕。每个单元格包含一个图像。这些图像从服务器下载并作为 UIImage 存储在自定义类(Card)中。当我显示该类对象数组中的图像时。
当我滚动时,图像有时会在错误的单元格处闪烁。我该如何纠正它?
CollectionViewController.swift
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCell", for: indexPath) as! ListViewCell
cell.configure(card: ClientSingleton.cards[indexPath.row])
cell.index = indexPath.row
return cell
}
Run Code Online (Sandbox Code Playgroud)
ListViewCell.swift
override func prepareForReuse() {
super.prepareForReuse()
imageView?.image = UIImage()
}
func configure(card: Card) {
imageView?.image = UIImage()
if let image = card.image {
self.image = image
self.setupImageView()
self.setupGyroBar()
self.setupGyro()
} else {
DispatchQueue.global(qos: .userInitiated).async {
card.loadImage() { image in
DispatchQueue.main.async {
self.image = image
self.setupImageView()
self.setupGyroBar()
self.setupGyro()
}
}
}
}
self.edgeColor = card.edgeColor
self.inverseEdgeColor = card.inverseEdgeColor
self.backgroundColor = self.edgeColor
}
Run Code Online (Sandbox Code Playgroud)
当单元格滚动到视图之外时,它们会被重用。在configure通话期间,当加载图像时,单元格可能会滚动到视图之外并被重新使用。
最简单的解决方案是在单元格中添加一些标识符,以便在图像加载完成时进行检查。您需要检查标识符是否仍然是您期望的那样。
CollectionViewController.swift
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ListCell", for: indexPath) as! ListViewCell
// Pass the row to the configure call so it can be used as an identifier
cell.configure(card: ClientSingleton.cards[indexPath.row], forIndex:indexPath.row)
return cell
}
Run Code Online (Sandbox Code Playgroud)
ListViewCell.swift
override func prepareForReuse() {
super.prepareForReuse()
imageView?.image = UIImage()
}
func configure(card: Card, forIndex index: Int) {
// Save the index as the identifier as the first thing you do,
// then check it in the async call.
self.index = index
imageView?.image = UIImage()
if let image = card.image {
self.image = image
self.setupImageView()
self.setupGyroBar()
self.setupGyro()
} else {
DispatchQueue.global(qos: .userInitiated).async {
card.loadImage() { image in
DispatchQueue.main.async {
if self.index == index {
// The cell is still being used for this index
self.image = image
self.setupImageView()
self.setupGyroBar()
self.setupGyro()
}
// else it is being used for another, so do not set the image
}
}
}
}
self.edgeColor = card.edgeColor
self.inverseEdgeColor = card.inverseEdgeColor
self.backgroundColor = self.edgeColor
}
Run Code Online (Sandbox Code Playgroud)
请注意,仅当行与要显示的图像之间存在对应关系时,此代码才有效。如果情况并非如此,您将需要使用更好的标识符来检查单元格是否仍然正确。