Lee Lee - 5 months ago 46
iOS Question

Weird behavior when scrolling and selecting in UICollectionView

I am having issues with displaying a checkmark on the a custom cell in a UICollectionView. For the first few taps everything works as expected, but when I begin scrolling or tapping repeatedly or click on the already selected cell, the behavior becomes odd as shown in the gif. Perhaps I am going about this in an incorrect way? The .addCheck() and .removeCheck() are methods inside the custom UICollectionViewCell class I made and all they do is add a checkmark image or remove one from the cell view. The odd behavior shown here

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

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ColorUICollectionViewCell

// Configure the cell
let color = colorList[(indexPath as NSIndexPath).row]
cell.delegate = self
cell.textLabel.text = color.name
cell.backgroundColor = color.color

if color.selected {
cell.addCheck()
}
else {
cell.removeCheck()
}

return cell
}

// user selects item
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

// set colors to false for selection
for color in colorList {
color.selected = false
}

// set selected color to true for selection
let color = colorList[indexPath.row]
color.selected = true
settings.backgroundColor = color.color
//userDefaults.set(selectedIndex, forKey: "selectedIndex")
collectionView.reloadData()
}


Below is what the addCheck() and removeCheck() functions in my custom cell look like.

func addCheck() {
// create check image
let checkImage = UIImage(named: "checkmark")
checkImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: bounds.size.height / 4, height: bounds.size.height / 4))
checkImageView.image = checkImage!.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
checkImageView.tintColor = UIColor.white()

// add the views
addSubview(checkImageView)
}

func removeCheck() {
if checkImageView != nil {
checkImageView.removeFromSuperview()
}
}

Answer

first off, you can simplify your didSelect a bit:

override func collectionView(collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    // set colors to false for selection
    for (index, color) in colorList.enumerate() {
        if index == indexPath.row {
            color.selected = false
            settings.backgroundColor = color.color
        }
        else {
            color.selected = false
        }
    }

    collectionView.reloadData()
}

Based on the language in your cellForItemAt method, I'm guessing you're adding a second check mark image when you tap on the same cell twice, and it's not being tracked properly so that cell just keeps getting rotated around overtime the collectionView's reloaded

Post your cell class, or at least the logic for addCheck and removeCheck and we might find the problem.

What I would recommend is permanently having an imageView with the check mark over the cell, when simple show/hide it based on the selection. This should speed up the collectionView as well.