11

I have a slide-out menu that I have implemented as a UICollectionViewController. I have created custom cells for the collection view as well. The navigation and everything works as expected. What I am having trouble with is changing the cells appearance when I click on an actual cell.

I've tried several approaches based on solutions(1)(2) I've seen here on stack but nothing to my satisfaction.

Solution 1: implement the UICollectionViewController delegate methods:

class SlideOutMenuViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout{
   //Setup code and other delegate methods….

    override func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SlideOutMenuCells

        cell.backgroundColor = .white
    }

    override func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! SlideOutMenuCells

        cell.backgroundColor = UIColor.mainGreen()
    }
}

When I tried this solution, nothing happens. The cells background color doesn't change colors.

Solution 2: This solution results in better results except the cell on changes colors when I hold the cell. I'd like the cells background color to flash or highlight quickly on a tap and not really just if the user holds the cell down.

class SlideOutMenuCells: UICollectionViewCell {

    //Setup code...

    override var isHighlighted: Bool {
        didSet {
            if self.isHighlighted {
                backgroundColor = UIColor.darkGreen()
            } else {
                backgroundColor = UIColor.mainGreen()
            }
        }
    }
}

Neither solution really works as intended. I've seen several posts here that try addressing this but haven't found one with a solution that works really. I would like the cell to flash highlight with a tap, and not just when a user clicks and holds on a cell...

mufc
  • 585
  • 3
  • 12
  • 29

4 Answers4

14

Here is working code for highlighting UICollectionViewCell on tap (swift 4 | swift 5)

Solution 1

class StoreCollViewCell:UICollectionViewCell{

    override var isSelected: Bool {
        didSet {
            self.contentView.backgroundColor = isSelected ? UIColor.red : UIColor.clear
        }
    }
}

Solution 2

Can't need to do anything in your UICollectionViewCell Class.

class StoreListViewController: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource {

    var previousSelected : IndexPath?
    var currentSelected : Int?

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "StoreCollViewCell", for: indexPath) as! StoreCollViewCell

        // To set the selected cell background color here
        if currentSelected != nil && currentSelected == indexPath.row
        {
            cell.backgroundColor = UIColor.green
        }else{
            cell.backgroundColor = UIColor.yellow
        }
    
        return cell     
    }

    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    
        // For remove previously selection 
        if previousSelected != nil{
            if let cell = collectionView.cellForItem(at: previousSelected!){
                cell.backgroundColor = UIColor.yellow
            }
        }
        currentSelected = indexPath.row
        previousSelected = indexPath

        // For reload the selected cell
        self.collVwStores.reloadItems(at: [indexPath]) 
    }
}

Output

enter image description here

enter image description here

Nikunj Kumbhani
  • 3,068
  • 1
  • 14
  • 43
10

I had the exact same problem and the solution is actually much simpler then the one posted above.

In your view controller, add collectionView.delaysContentTouches = false.

And then your other code within the cell was fine as is:

class SlideOutMenuCells: UICollectionViewCell {

    //Setup code...

    override var isHighlighted: Bool {
        didSet {
            if self.isHighlighted {
                backgroundColor = UIColor.darkGreen()
            } else {
                backgroundColor = UIColor.mainGreen()
            }
        }
    }
}

But now that annoying delay is gone!

M Somerville
  • 3,938
  • 25
  • 37
Kevin Renskers
  • 3,331
  • 2
  • 30
  • 66
3

You can try to use UILongPressGestureRecognizer to indicate selection:

override func awakeFromNib() {
    super.awakeFromNib()

    let tapGesture = UILongPressGestureRecognizer(target: self, action: #selector(didTap(recognizer:)))
    tapGesture.minimumPressDuration = 0
    tapGesture.cancelsTouchesInView = false
    addGestureRecognizer(tapGesture)
}

@objc func didTap(recognizer: UILongPressGestureRecognizer) {
    if recognizer.state == .began {
        backgroundColor = .red
    }
    if recognizer.state == .ended {
        backgroundColor = .green
    }
}

or you can make extension for UICollectionViewCell

extension UICollectionViewCell {
func makeSelectionIndicatable() {
    let tapGesture = UILongPressGestureRecognizer(target: self, action: #selector(didTap(recognizer:)))
    tapGesture.minimumPressDuration = 0
    tapGesture.cancelsTouchesInView = false
    addGestureRecognizer(tapGesture)
}

@objc private func didTap(recognizer: UILongPressGestureRecognizer) {
    if recognizer.state == .began {
        backgroundColor = .red
    }
    if recognizer.state == .ended {
        backgroundColor = .green
    }
}

}

and after that for any cell at awakeFromNib() method you just need to add makeSelectionIndicatable()

rubik
  • 514
  • 3
  • 15
0

You can do this by changing the color if content view in cell like:

class SlideOutMenuCells: UICollectionViewCell {

override var isSelected: Bool {
    didSet {
        self.contentView.backgroundColor = isSelected ? OLTheme.Colors.Selected_Voucher_Color : UIColor.clear
    }
} 
}
Adnan Munir
  • 129
  • 7