Parcker
Parcker

Reputation: 219

Change color of selected cell in CollectionView depends on condition

I need to set gradient cell color in CollectionView for different conditions.

enter image description here

The conditions are set in ViewController in didSelectItemAt method:

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

        if cellNumbers[indexPath.item] == currentNumberGuess {
            updateNumberLabel()
}
    }

I managed to change the color of cells in UICollectionViewCell:

class CollectionViewCell: UICollectionViewCell {

    private lazy var gradient: CAGradientLayer = {
        let gradientLayer = CAGradientLayer()
        gradientLayer.colors = [UIColor.systemGreen.cgColor, UIColor.green.cgColor]
        gradientLayer.startPoint = CGPoint(x: 0, y: 0)
        gradientLayer.endPoint = CGPoint(x: 1, y: 1)
        gradientLayer.frame = self.bounds
        return gradientLayer
    }()

    override var isSelected: Bool {
        didSet {
            if self.isSelected {
                self.layer.insertSublayer(self.gradient, at: 0)
                label.isHidden = true
            } else {
                self.gradient.removeFromSuperlayer()
            }
        }
    }

    
    @IBOutlet weak var label: UILabel!
}

But I also need to change color of selected cell depends on cellNumbers[indexPath.item] == currentNumberGuess condition. How I can do that?

Upvotes: 2

Views: 1126

Answers (2)

Eric Hua
Eric Hua

Reputation: 1015

Try this:

  1. Remove your override var isSelected code.
  2. Move your gradient definition to your ViewController and make it a function instead:
private func getGradient(for cell: UICollectionViewCell) -> CAGradientLayer {
    let gradientLayer = CAGradientLayer()
    gradientLayer.colors = [UIColor.systemGreen.cgColor, UIColor.green.cgColor]
    gradientLayer.startPoint = CGPoint(x: 0, y: 0)
    gradientLayer.endPoint = CGPoint(x: 1, y: 1)
    gradientLayer.frame = cell.bounds

    return gradientLayer
}
  1. Change the color in your didSelectItemAt function, you can get the instance of your cell like this:
private var previousGradientLayer: CAGradientLayer?

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    if cellNumbers[indexPath.item] == currentNumberGuess {
        guard let cell = collectionView.cellForItem(at: indexPath) else { return }

        // Clear gradient of the previously selected cell
        self.previousGradientLayer?.removeFromSuperlayer()

        // Update previousGradientLayer to the new gradient
        self.previousGradientLayer = self.getGradient(for: cell)

        // Your code
        cell.layer.insertSublayer(self.previousGradientLayer!, at: 0)
        label.isHidden = true
    }
}

Upvotes: 2

PGDev
PGDev

Reputation: 24341

You can use closure for handling this.

1. Create a handler in CollectionViewCell and call it when isSelected is true, i.e.

var handler: (()->(Bool))? 

override var isSelected: Bool {
    didSet {
        if self.isSelected {
            if let value = self.handler?(), value {
                self.layer.insertSublayer(self.gradient, at: 0)
                label.isHidden = true
            }
        } else {
            self.gradient.removeFromSuperlayer()
        }
    }
}

2. Set the value of handler in collectionView(_:cellForItemAt:) method

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
    cell.handler = {
        return cellNumbers[indexPath.item] == currentNumberGuess
    }
    return cell
}

3. In collectionView(_:didSelectItemAt:) reload the cell at indexPath

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    collectionView.reloadItems(at: [indexPath])
}

Upvotes: 1

Related Questions