Select only one item in UICollectionViewController

Viewed 4431

I've implemented a subclass of UICollectionViewController which is horizontally scrollable and I want it to be able to select ONLY one item at time.

It works fine when I change the selected item on the current screen. However, for example, if I select an item at the very beginning of the collection and then scroll to the right and select another one the first one will still be selected.

Here's the current version of my CollectionView:

class GenresCollectionVC: UICollectionViewController {

    var selectedIndexPath: IndexPath?

    // MARK: UICollectionViewDataSource
    override func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return MockData.instance.genres.count
    }

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

        cell.genreNameLabel.text = MockData.instance.genres[indexPath.row]
        if selectedIndexPath == indexPath {
            redraw(selectedCell: cell)
        } else {
            redraw(deselectedCell: cell)
        }

        return cell
    }

    // MARK: UICollectionViewDelegate
    override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? GenreCollectionViewCell else {
            return
        }
        redraw(selectedCell: cell)
        selectedIndexPath = indexPath
    }

    override func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
        guard let cell = collectionView.cellForItem(at: indexPath) as? GenreCollectionViewCell else {
            return
        }
        redraw(deselectedCell: cell)
        selectedIndexPath = nil
    }

    private func redraw(selectedCell cell: GenreCollectionViewCell
        ) {
        cell.layer.borderWidth = 1.0
        cell.layer.cornerRadius = cell.bounds.height / 2
        cell.layer.borderColor = UIColor.violetNeeoColor.cgColor

        cell.genreNameLabel.textColor = UIColor.violetNeeoColor
    }

    private func redraw(deselectedCell cell: GenreCollectionViewCell) {
        cell.layer.borderWidth = 0.0
        cell.layer.cornerRadius = 0.0

        cell.genreNameLabel.textColor = UIColor.white
    }
}

What am I doing wrong?

4 Answers
private var selectedIndexPath: IndexPath? = nil

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "tagcell", for: indexPath) as! TagCell
        cell.title = items[indexPath.item]
        cell.isSelected = selectedIndexPath == indexPath
        return cell
    }

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){
        if selectedIndexPath != nil {
            if indexPath != selectedIndexPath {
                selectedIndexPath = indexPath
            }
        } else {
            selectedIndexPath = indexPath
        }

        collectionView.reloadItems(at: collectionView.indexPathsForVisibleItems)
    }
Related