swiftyboi
swiftyboi

Reputation: 3221

How can I highlight selected UICollectionView cells? (Swift)

I have a UICollectionView, and the user is able to select multiple cells. It's a bit difficult to keep track of which cells have been selected, so I need some way to go about highlighting/creating a border when the cell is tapped.

Code:

func collectionView(collectionView: UICollectionView, shouldSelectItemAtIndexPath indexPath: NSIndexPath) -> Bool {

    addToList.append(objectsArray[indexPath.row])

    return true

}

Upvotes: 29

Views: 73976

Answers (9)

drfalcoew
drfalcoew

Reputation: 674

SWIFT

Add this code to your UICollectionViewCell subclass:

 override var isSelected: Bool {
    didSet{
        if self.isSelected {
            UIView.animate(withDuration: 0.3) { // for animation effect
                 self.backgroundColor = UIColor(red: 115/255, green: 190/255, blue: 170/255, alpha: 1.0)
            }
        }
        else {
            UIView.animate(withDuration: 0.3) { // for animation effect
                 self.backgroundColor = UIColor(red: 60/255, green: 63/255, blue: 73/255, alpha: 1.0)
            }
        }
    }
}

This will set the color of a single selected cell, and remove the selected color from any previous selected cells. I've added a smooth animation to it. I think it's nice, but it's optional.

Upvotes: 22

Kamnev Vladimir
Kamnev Vladimir

Reputation: 1

With ternary operator

  override var isSelected: Bool {
        didSet {
                        UIView.animate(withDuration: 0.3) {
                            self.backgroundColor = self.isSelected ? .systemGray4 : .systemGray6
                        }
                    }
                }

Upvotes: 0

Jayaseelan Kumarasamy
Jayaseelan Kumarasamy

Reputation: 33

Try this code to highlight collection view cell

func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) {
        cell.contentView.backgroundColor = #colorLiteral(red: 1, green: 0.4932718873, blue: 0.4739984274, alpha: 1)
    }
}

func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
    if let cell = collectionView.cellForItem(at: indexPath) {
        cell.contentView.backgroundColor = nil
    }
}

Upvotes: 1

DawnSong
DawnSong

Reputation: 5202

Here is my solution, and I'm sure it works.

My solution includes 3 highlight effects, UICollectionCell's selectedBackgroundView, cell.contentView.backgroundColor, or your your own specialHighlightedArea; just feel free to choose the one you need, and feel free to add more effects as your App's Designer requires.

How to use? Just inherit BaseCollectionViewCell. If needed, configure in cell's init or collectionView's delegate methods.

If you don't need highlight effect, just find a method named 'shouldHighlightItemAtIndexPath' in UICollectionViewDelegate and return false or just set cell.shouldTintBackgroundWhenSelected = false.

extension UIColor {
    convenience init(rgb: Int, alpha: CGFloat = 1.0) {
        self.init(red: CGFloat((rgb & 0xFF0000) >> 16) / 255.0, green: CGFloat((rgb & 0xFF00) >> 8) / 255.0, blue: CGFloat(rgb & 0xFF) / 255.0, alpha: alpha)
    }
}
/// same with UITableViewCell's selected backgroundColor
private let cellHighlightedColor = UIColor(rgb: 0xD8D8D8) 

class BaseCollectionViewCell: UICollectionViewCell {

    var shouldTintBackgroundWhenSelected = true // You can change default value
    var specialHighlightedArea: UIView?

    // make lightgray background show immediately(on touch)
    // (使灰背景在手指触到 cell 时立即出现)
    override var isHighlighted: Bool { 
        willSet {
            onSelected(newValue)
        }
    }
    // keep lightGray background from selected until unselected 
    // (保留灰背景直至取消选中)
    override var isSelected: Bool { 
        willSet {
            onSelected(newValue)
        }
    }
    func onSelected(_ newValue: Bool) {
        // selectedBackgroundView is defined by UICollectionViewCell
        guard selectedBackgroundView == nil else { return }
        if shouldTintBackgroundWhenSelected {
            contentView.backgroundColor = newValue ? cellHighlightedColor : UIColor.clear
        }
        if let sa = specialHighlightedArea {
            sa.backgroundColor = newValue ? UIColor.black.withAlphaComponent(0.4) : UIColor.clear
        }
    }
}

Upvotes: 18

H S W
H S W

Reputation: 7129

For multiple selection of cell, you can do it as follow:

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

    if let currentCell = collectionView.cellForItem(at: indexPath) as? QuestionnaireCollectionViewCell {

        // Your selection logic, you can change it according to your requirement
       if currentCell.selectedImage.isHidden == true{
           currentCell.selectedImage.isHidden = false

       }
       else{
          currentCell.selectedImage.isHidden = true
       }
    }

    }

}

For single selection you can use isSelected in your collectionviewcell class as follow:

 override var isSelected: Bool{
   didSet{
     if self.isSelected
     {
     //This block will be executed whenever the cell’s   selection state is set to true (i.e For the selected cell)
     }
    else
     {
     //This block will be executed whenever the cell’s selection state is set to false (i.e For the rest of the cells)
     }
   }
}

Upvotes: 4

Strong84
Strong84

Reputation: 1979

You can create a customized collcetionViewCell, and override:

class MyCell: UICollectionViewCell {

    override var isHighlighted: Bool {
        didSet {
            if self.isHighlighted {
                print("yes")
                // Your customized animation or add a overlay view
            } else {
                print("no")
                // Your customized animation or remove overlay view
            }
        }
    }
}

This way, you can create similar result like the highlight effect on UITableViewCell.

Without subclassing:

If you don't want to create your own collectionViewCell. you can use the delegate method:

func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath)

func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath)

You can do the same thing with it.

Upvotes: 6

Deepansh Jagga
Deepansh Jagga

Reputation: 109

Try to make the borders thick enough to cover the entire cell

Code:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    addToList.append(objectsArray[indexPath.row])
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.layer.borderWidth = 200.0
    cell?.layer.borderColor = UIColor.init(red: 0/255, green: 0/255, blue: 0/255, alpha: 0.4).cgColor
}

Upvotes: 0

Özgür Ersil
Özgür Ersil

Reputation: 7013

you can use border change on didSelectItemAtIndexPath override event like the below code and assign new settings on the cell.

Swift 3.x:

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    addToList.append(objectsArray[indexPath.row])
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.layer.borderWidth = 2.0
    cell?.layer.borderColor = UIColor.gray.cgColor
}

Upvotes: 53

Sunkas
Sunkas

Reputation: 9590

Use

collectionView.reloadItemsAtIndexPaths([indexPath])

to reload current cell, or

collectionView.reloadData()

to reload all cells in shouldSelectItemAtIndexPath

Then in cellForItemAtIndexPath set your border or background color if the cell is marked as checked (you may need a new array for checked cells with preferably indexPaths.

Upvotes: 6

Related Questions