UICollectionView 图像在滚动时混合

Mit*_*dal 3 ios swift

我正在制作一个应用程序,其中集合的单个单元格占据整个屏幕。每个单元格包含一个图像。这些图像从服务器下载并作为 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)

Gar*_*kin 5

当单元格滚动到视图之外时,它们会被重用。在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)

请注意,仅当行与要显示的图像之间存在对应关系时,此代码才有效。如果情况并非如此,您将需要使用更好的标识符来检查单元格是否仍然正确。