简体   繁体   中英

Allow one button in collection view cell to be tapped and updated at a time

When a button gets tapped within a Collection View, the border color of the button gets updated to yellow and also reflects that it has been selected. If I tap on another button, I want to be able to update the border to yellow but also change the previous button's border to the original color black.

Attempted this solution: How to highlight selection only one button at a time from multiple buttons using Swift but was unable to change the previous button to the original color.

My current code

let buttonTitles: [String] = ["Red", "Blue", "Green", "Orange", "Gray"]
var isChosen: Bool = false 


@objc func selectAction(_ sender: UIButton) {
    let tag = sender.tag
    print(tag)

    isChosen = true
    if tag == 1 {
        sender.borderColor = .yellow
        sender.borderWidth = 5

    } else if tag == 2 {
            sender.borderColor = .black
            sender.borderWidth = 1
    }
    isChosen = !isChosen

 }


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return buttonTitles.count
}

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

    cell.colorsButton.setTitle(timeOptions[indexPath.row], for: .normal)
    cell.colorsButton.tag = indexPath.row
    cell.colorsButton.addTarget(self, action: #selector(selectAction(_:)), for: .touchUpInside)

    return cell
}

You can keep track of the selectedButton indexPath by declaring a variable:

var selectedButtonIndexPath: IndexPath?

Then inside cellForItemAt, you can define what the button looks like when selected:

if indexPath == selectedButtonIndexPath { // If button is selected
    cell.colorsButton.layer.borderColor = UIColor.yellow.cgColor
    cell.colorsButton.layer.borderWidth = 5

} else { // If it is not selected
    cell.colorsButton.layer.borderColor = UIColor.black.cgColor
    cell.colorsButton.layer.borderWidth = 1
}

Finally, inside your selectAction function:

@objc func selectAction(_ sender: UIButton) {
    /* First let's get a reference to the cell that contains the newly selected button. Make sure you get the correct amount of superviews in there.. it depends on how you laid out your cells */
    guard let newlySelectedButtonCell = sender.superview?.superview as? ColorsCollectionCell else { return }
    // Let's find out the indexPath for the newly selected button
    guard let newlySelectedButtonCellIndexPath = collectionView.indexPath(for: newlySelectedButtonCell) else { return }
    // If previously selected button and newly selected button are the same, simply deselect button
   if newlySelectedButtonCellIndexPath == selectedButtonIndexPath {
      newlySelectedButtonCell.colorsButton.layer.borderColor = UIColor.black.cgColor
      newlySelectedButtonCell.colorsButton.layer.borderWidth = 1
      selectedButtonIndexPath = nil
      return
   }
    // If newly selected button is different than previously selected button...
    // First change the look for previously selected button
    if let indexPath = selectedButtonIndexPath, let previouslySelectedButtonCell = collectionView.cellForItem(at: indexPath) as? ColorsCollectionCell { 
        newlySelectedButtonCell.colorsButton.layer.borderColor = UIColor.black.cgColor
        newlySelectedButtonCell.colorsButton.layer.borderWidth = 1
    }

    // Now change the look of newly selected button
    newlySelectedButtonCell.layer.borderColor = UIColor.yellow.cgColor
    newlySelectedButtonCell.layer.borderWidth = 5

    selectedButtonIndexPath = newlySelectedButtonCellIndexPath

 }

There is an easier way to code the last function, and that would be to simply change the value of selectedButtonIndexPath and call reloadData() to update the collectionView. But it's not optimal:

@objc func selectAction(_ sender: UIButton) {
    guard let newlySelectedButtonCell = sender.superview?.superview as? ColorsCollectionCell else { return }
    guard let newlySelectedButtonCellIndexPath = collectionView.indexPath(for: newlySelectedButtonCell) else { return }
    if newlySelectedButtonCellIndexPath != selectedButtonIndexPath {
        selectedButtonIndexPath = newlySelectedButtonCellIndexPath
    } else { // If same button selected, deselect? Unless you want a different behavior
        selectedButtonIndexPath = nil
    }

    collectionView.reloadData()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM