【问题标题】:UIButton image for normal state in collectionview cell repeats itself every four cells集合视图单元格中正常状态的 UIButton 图像每四个单元格重复一次
【发布时间】:2019-02-05 15:03:13
【问题描述】:

我正在尝试为位于 collectionView 单元格中的按钮的正常状态设置图像。按下按钮时,图像会发生变化。问题是每四个单元格在按下按钮时重复与原始单元格相同的图像。有没有办法让它不重复,当按下按钮时,它只针对那个单独的单元格?

代码如下:

class FavoritesCell: UICollectionViewCell {

  var isFavorite: Bool = false

  @IBOutlet weak var favoritesButton: UIButton!

  @IBAction func favoritesButtonPressed(_ sender: UIButton) {
        _ = self.isFavorite ? (self.isFavorite = false, self.favoritesButton.setImage(UIImage(named: "favUnselected"), for: .normal)) : (self.isFavorite = true, self.favoritesButton.setImage(UIImage(named: "favSelected"), for: .selected))

    }
}

我尝试过这样做,但由于某种奇怪的原因,即使按下按钮,也不会显示“选定”状态图像:

let button = UIButton()

override func awakeFromNib() {
    super.awakeFromNib()

    button.setImage(UIImage(named: "favUnselected"), for: .normal)
    button.setImage(UIImage(named: "favSelected"), for: .selected)
}

【问题讨论】:

  • 细胞被重复使用。重置cellForItemAt中的状态。
  • @rmaddy 问题是我希望它保存 uibutton 正常状态的图像,如果它发生变化并且用户滚动回原始单元格。
  • 没错。这就是为什么您需要将状态存储在数据模型中,并在每次cellForItemAt 中相应地重置单元格。
  • @rmaddy 我不完全确定该怎么做,当我在按下按钮后打印状态时,我得到: UIControlState(rawValue: 1)
  • 在 cellForRowAt 方法中创建单元格时,请确保应选择哪个单元格的按钮。每个单元格。

标签: ios swift uicollectionview uicollectionviewcell


【解决方案1】:

每次您的单元格出列时都会调用cellForItemAt。这是您配置单元数据的地方。因此,如果您需要显示标记为收藏的单元格,可以在此处进行。

那么你是怎么做到的呢?假设您的所有单元格一开始都没有被选中。美好的。您不必在cellForItemAt 中说任何话。现在假设您将一些单元格标记为收藏。这里发生的情况是,当单元格可见时,它将反映更改,因为按钮已连接到将进行更改的选择器。

现在问题来了。当您滚动 并且单元格消失时,有关您的单元格被标记为收藏的信息将丢失!因此,您需要做的是维护一个数组,该数组将存储所有选定单元格的IndexPath。 (确保从收藏夹中删除单元格时删除IndexPath!)让我们将该数组称为favourites。如果您可以将数据源用于集合视图来存储选定的状态信息,那也很好。现在您必须在按钮选择器中存储有关您的单元格是否被标记为收藏的信息。

@objc func buttonTapped() {
    if favourites.contains(indexPath) {   // Assuming you store indexPath in cell or get it from superview
        favourites.removeAll(where: {$0 == indexPath})
    } else {
        favourites.append(indexPath)
    }
}

存储单元格信息后,每次出列单元格时,都需要检查IndexPath是否为favourites。如果是,则调用将单元格设置为选定状态的方法。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    // Dequeue cell and populating cell with data, etc
    if favourites.contains(indexPath) {
        cell.showFavourite()
    }
}

完成了吗?不!现在我们还有另一个问题。此问题与单元格的重用有关。那么cellForItemAt 实际上会发生什么?您出列一个单元格并使用它来显示信息。因此,当您将其出列时,它可能已经用于在其他索引路径中显示其他信息。因此,那里存在的所有数据都将保留。 (这就是为什么您会遇到收藏夹每 4 个单元格重复一次的问题!)

那么我们该如何解决呢? UICollectionViewCell 中有一个方法称为 before 单元格出列 - prepareCellForReuse。您需要在您的单元格中实现此方法并从单元格中删除所有信息,以便它到达cellForItemAt 时是新鲜的。

func prepareForReuse() {
     //Remove label text, images, button selected state, etc
}

或者您可以始终在cellForItemAt 中设置单元格内所有内容的每个值,以便始终用必要的值覆盖每个信息。

编辑:OP 说他在集合视图中有一个集合视图。你可以像这样识别哪个集合视图被调用,

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if collectionView === favoriteCollectionView { // This is the collection view which contains the cell which needs to be marked as favourite
        // Dequeue cell and populating cell with data, etc
        if favourites.contains(indexPath) {
            cell.showFavourite()
        }
        return cell
    }
    // Dequeue and return for the other collectionview
}

【讨论】:

  • 这很好,但我一次有 2 个集合视图单元格(为了获得水平滚动),一个单元格嵌入在另一个单元格中(包含 collectionView),我将如何获得嵌入的 indexPath细胞?
  • @SwiftyJD 如果您有 2 个集合视图,您可以通过将委托中的集合视图与您自己的进行比较来检查委托中正在对哪个集合视图进行操作。然后您将需要 2 个数组或使用它们各自的数据源来存储收藏信息。如果您只有一个 collectionView 中的收藏夹,则检查该收藏夹视图是否是您在相应委托中的收藏夹视图,并调用该方法将该单元格标记为该单元格中的收藏夹。
  • 是的,第一个单元格内有一个collectionView,在collectionView 内部是另一个collectionView 单元格,其中包含带有按钮的视图
  • @SwiftyJD 我建议你分享你写的cellForItemAt 代表。
  • 我用两个collectionview单元格代码更新了问题
【解决方案2】:

单元格很可能被重复使用,并且您的 isFavorite 设置为 true

尝试添加

func prepareForReuse() {
    super.prepareForReuse()
    self.isFavorite = false
}

当单元格被重复使用时,这会将按钮设置为原始图像。

另外,既然你的按钮有selected 的两种状态,为什么要跳这个舞

  _ = self.isFavorite ? (self.isFavorite = false, self.favoritesButton.setImage(UIImage(named: "favUnselected"), for: .normal)) : (self.isFavorite = true, self.favoritesButton.setImage(UIImage(named: "favSelected"), for: .selected))

你只能说self.favoritesButton.selected = self.isFavorite

将您的单元格代码更改为:

class FavoritesCell: UICollectionViewCell {
    @IBOutlet weak var favoritesButton: UIButton!

    var isFavorite: Bool = false {
        didSet {
            favoritesButton.selected = isFavorite
        }
    }

    @IBAction func favoritesButtonPressed(_ sender: UIButton) {
        favoritesButton.selected = !favoritesButton.selected       
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        isFavorite = false
    }
}

【讨论】:

  • 我刚试过这个,它仍然出于某种奇怪的原因重复
  • 这适用于在选择单元格时取消选择其他单元格,但是当滚动到第一个被选中的单元格时,它不会保持选中状态,它现在也处于未选中状态。
  • 那么您需要跟踪的不是在单元格中,而是在呈现UICollectionViewViewController 中基本上有一个喜欢的IndexPaths 数组,然后您必须配置当您执行cellForItemAt: 时,单元格状态正确
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
  • 2021-10-06
相关资源
最近更新 更多