Search code examples
swiftif-statementbuttonbackground-colorcollectionview

Swift: How to switch/change button color by selecting another button in CollectionView?


ViewController has two horizontal collectionViews and tableView. One of the collections should display the categories (enum) in the buttons from the model (StoriesModel). Click the button select the category of articles the user wants to read in the TableView.

When the user clicks the button, it changes color to .blue. Need when the user clicks on the next button (selecting a new category of articles), the button changes color to .blue, and the previous button (category) becomes .clear color. Now, when I click a button it changes color, but when I click next button it become .blue, but doesn't deselect the previous button color to .clear

CollectionViewCell:

//MARK: CollectionView Stories Buttons Protocol
protocol StoriesCollectionButtonsDelegate: AnyObject {
    func didSelectButton(at index: Int)
}

class StoryCategoryCollectionViewCell: UICollectionViewCell {
    
    //MARK: Category Outlets
    @IBOutlet weak var categoryButton: UIButton!
    
    //MARK: Static Properties
    static let categoryCellIdentifier = "StoryCategoryCollectionViewCell"
    
    //MARK: Properties
    var storiesName: StoriesName?
    
    //MARK: Button Delegate
    weak var delegateButtons: StoriesCollectionButtonsDelegate?
    
    //MARK: isSelectedButton
    var isSelectedButton: Bool = true {
        didSet {
            categoryButton.backgroundColor = isSelectedButton ? .clear : .blue
        }
    }
    
    //MARK: Awake From Nib
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
        setUpStoryCategory()
        
        categoryButton.addTarget(self, action: #selector(selectedButton), for: .touchUpInside)
    }
    
    //MARK: CollectionView Stories Buttons Action
    @objc private func selectedButton() {
        delegateButtons?.didSelectButton(at: self.tag)
        isSelectedButton = !isSelectedButton
    }
}

//MARK: Category Private Methods
extension StoryCategoryCollectionViewCell {
    private func setUpStoryCategory() {
        categoryButton.tintColor = .white
        categoryButton.layer.cornerRadius = categoryButton.frame.size.height / 2
        categoryButton.clipsToBounds = true
        categoryButton.layer.borderColor = UIColor.white.cgColor
        categoryButton.layer.borderWidth = 2
    }
    
    //MARK: Blue Color Home Button 
    func setUpCategoryCollectionViewCell(data: StoriesCategory) {
        guard let category = StoriesName(rawValue: data.Category ?? 0) else {
            return
        }
        categoryButton.setTitle(category.storiesName, for: .normal)
        
        categoryButton.setTitleColor(.white, for: .normal)

        if data.Category == 0 {
            categoryButton.backgroundColor = .blue
        } else {
            categoryButton.backgroundColor = .clear
        }
    }
}

ViewController:

//MARK: - UICollectionViewDelegate
extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        //let item = stories[indexPath.row]
        let item = StoriesName.allCases[indexPath.row]
        self.selectedCategory = item
        switch item {
        case .Home:
            return()
        case .Zabava:
            return()
        case .Muzika:
            return()
        case .Životni_stil:
            return()
        case .Događaj:
            return()
        case .Sport:
            return()
        case .Tehnologija:
            return()
        case .Zdravlje:
            return()
        }
    }
}

//MARK: - UICollectionViewDataSource
extension ViewController: UICollectionViewDataSource {
    
  // ... 

      } else if collectionView == storiesCollection {
            guard let categoryCell = collectionView.dequeueReusableCell(withReuseIdentifier: StoryCategoryCollectionViewCell.categoryCellIdentifier, for: indexPath) as? StoryCategoryCollectionViewCell else {
                return UICollectionViewCell()
            }
            let item = stories[indexPath.row]
            categoryCell.setUpCategoryCollecti
//MARK: CollectionView Stories Buttons Delegate
extension SeTvPlusViewController: StoriesCollectionButtonsDelegate {
    func didSelectButton(at index: Int) {
        if let previousIndex = selectedButtonIndex,
           let previousCell = storiesCollection.cellForItem(at: IndexPath(item: previousIndex, section: 0)) as? StoryCategoryCollectionViewCell {
            previousCell.isSelectedButton = false
            
            switch previousCell.storiesName {
            case .Home:
                previousCell.categoryButton.backgroundColor = .clear
            default:
                previousCell.categoryButton.backgroundColor = .clear
            }
        }
        
        if let currentCell = storiesCollection.cellForItem(at: IndexPath(item: index, section: 0)) as? StoryCategoryCollectionViewCell {
            currentCell.isSelectedButton = true
            currentCell.categoryButton.backgroundColor = .blue
        }
        
        selectedButtonIndex = index
    }
}
onViewCell(data: item)
            //MARK:
            categoryCell.delegateButtons = self
                    return categoryCell
        }
        return UICollectionViewCell()
    }
}

I define a protocol named StoriesCollectionButtonsDelegate. Declare a weak property named delegateButtons. Declare a property named isSelectedButton to update the background color. Set a private method selected button that is called when the button inside the cell is tapped.

Declare two properties: selectedButtonIndex, which represents the index of the currently selected button in the collection view, and selectedCategory, which represents the currently selected category of stories.

In the UICollectionViewDelegate protocol. It implements the collectionView(_:didSelectItemAt:) method, which is called when an item (cell) in the collection view is selected.

And extend ViewController with StoriesCollectionButtonsDelegate protocol, which is responsible for handling button selection events in the collection view cells

Need that clicking on a category button changes the color of the button, so that selecting the next category deselects the previous button and becomes. clear and the selected category button becomes .blue


Solution

  • I managed to solve the task, I guess this is not the only way. I hope this solution will help someone.

    1. All buttons in the collection have only two states, On and Off
    2. In the On status, the button is .blue, in the Off status, the button is .clear
    3. Clicking on the button changes the status of the button from Off to On and changes its color from .blue to .clear
    4. When the same button that is in On status is clicked a second time, the button does not change its status and does not change its color
    5. The status from On to Off can only be changed by clicking on another button from the collection
    6. Each button in the collection can change the state of each button in the collection
    7. By default, the Home button is in the On status when the ViewContoller is opened, but when any button from collections is clicked the Home button should change status to Off.

    Cell:

    /MARK: CollectionView Stories Buttons Protocol
    protocol StoriesCollectionButtonsDelegate: AnyObject {
        func didSelectButton(at index: Int)
    }
    
    class StoryCategoryCollectionViewCell: UICollectionViewCell {
    
        //MARK: Category Outlets
        @IBOutlet weak var categoryButton: UIButton!
    
        //MARK: Static Properties
        static let categoryCellIdentifier = "StoryCategoryCollectionViewCell"
    
        //MARK: Properties
        var storiesName: StoriesName?
        var isSelectedButton: Bool = false {
            didSet {
                updateButtonAppearance()
            }
        }
    
        weak var delegateButtons: StoriesCollectionButtonsDelegate?
    
        private func updateButtonAppearance() {
               if isSelectedButton {
                   categoryButton.backgroundColor = .blue
               } else {
                   categoryButton.backgroundColor = .clear
               }
           }
    
           //MARK: Awake From Nib
           override func awakeFromNib() {
               super.awakeFromNib()
               // Initialization code
               categoryButton.addTarget(self, action: #selector(selectedButton), for: .touchUpInside)
               setUpStoryCategory()
           }
        
        //MARK: CollectionView Stories Buttons Action
            @objc private func selectedButton() {
                if !isSelectedButton {
                    delegateButtons?.didSelectButton(at: self.tag)
                }
            }
        
        private func setUpStoryCategory() {
            categoryButton.tintColor = .white
            categoryButton.layer.cornerRadius = categoryButton.frame.size.height / 2
            categoryButton.clipsToBounds = true
            categoryButton.layer.borderColor = UIColor.white.cgColor
            categoryButton.layer.borderWidth = 2
        }
    
            //MARK: Set Up Category Cell
        func setUpCategoryCell(data: StoriesCategory, isSelected: Bool) {
            guard let category = StoriesName(rawValue: data.Category ?? 0) else {
                return
            }
            storiesName = category
            categoryButton.setTitle(category.storiesName, for: .normal)
            categoryButton.setTitleColor(.white, for: .normal)
    
            if category == .Home {
                categoryButton.isUserInteractionEnabled = false
                isSelectedButton = true
            } else {
                categoryButton.isUserInteractionEnabled = true
                isSelectedButton = isSelected
            }
        }
    }
    

    ViewController:

        //MARK: Currently Selected Button Property
        var selectedButtonIndex: Int?
        var selectedCategory: StoriesName = .Home
    
    //MARK: - UICollectionViewDelegate
        extension ViewController: UICollectionViewDelegate {
            func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                let item = StoriesName.allCases[indexPath.row]
                self.selectedCategory = item
                collectionView.reloadData()
            }
        }
    
    
    //MARK: - UICollectionViewDataSource
     extension ViewController: UICollectionViewDataSource {
         func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
             if collectionView == chooseCollection {
                 return featuredStoryList.count
             } else if collectionView == storiesCollection {
                 return stories.count
             }
             return 0
         }
         func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
                    if collectionView == chooseCollection {
                        guard let storyCell = collectionView.dequeueReusableCell(withReuseIdentifier: ChooserCollectionViewCell.cellIdentifier, for: indexPath) as? ChooserCollectionViewCell else {
                            return UICollectionViewCell()
                        }
                        let item = featuredStoryList[indexPath.row]
                        storyCell.setUpStroyDetailCell(data: item)
                        return storyCell
                    } else if collectionView == storiesCollection {
                        guard let categoryCell = collectionView.dequeueReusableCell(withReuseIdentifier: StoryCategoryCollectionViewCell.categoryCellIdentifier, for: indexPath) as? StoryCategoryCollectionViewCell else {
                            return UICollectionViewCell()
                        }
                        let item = stories[indexPath.row]
                        let isSelected = (selectedCategory.rawValue == item.Category)
                        categoryCell.setUpCategoryCell(data: item, isSelected: isSelected)
                        categoryCell.delegateButtons = self
                        categoryCell.tag = indexPath.row
                        return categoryCell
                    }
                    return UICollectionViewCell()
        }
    }
    
    //MARK: - StoriesCollectionButtonsDelegate
    extension ViewController: StoriesCollectionButtonsDelegate {
        func didSelectButton(at index: Int) {
            guard let selectedCell = storiesCollection.cellForItem(at: IndexPath(item: index, section: 0)) as? StoryCategoryCollectionViewCell else {
                return
            }
            
            if let previousIndex = selectedButtonIndex,
               let previousCell = storiesCollection.cellForItem(at: IndexPath(item: previousIndex, section: 0)) as? StoryCategoryCollectionViewCell {
                previousCell.isSelectedButton = false
            }
            
            selectedCell.isSelectedButton.toggle()
            selectedButtonIndex = index
    
            if selectedCell.storiesName == .Home {
                selectedCell.isSelectedButton = true
                for cell in storiesCollection.visibleCells {
                    if let storyCell = cell as? StoryCategoryCollectionViewCell, storyCell.storiesName != .Home {
                        storyCell.isSelectedButton = false
                    }
                }
            } else if let homeCell = storiesCollection.cellForItem(at: IndexPath(item: 0, section: 0)) as? StoryCategoryCollectionViewCell {
                homeCell.isSelectedButton = false
            }
        }
    }