UICollectionView - random cells are selected

2020-04-20 08:34发布

I have a Horizontal UICollectionView like the horizontal Calender in iOS. Paging is enabled but not allowsMultipleSelection.

self.allowsMultipleSelection = false
self.isPagingEnabled = true

There are only 5 cells per page.

 let cellSize =    CGSize(width: self.view.frame.width / 5 , height: 60)

CollectionView's height is also 60.

didSelectItemAt change background color to .red and didDeselectItem resets it to .white.

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

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

The collection view has multiple sections and rows. If I select a cell in the first visible page and scroll, random cells are selected in the next visible pages. That is to say random cells are red in the next pages. I do not want this to be so. I want to select/change color of cells manually.

How can I fix this?

3条回答
聊天终结者
2楼-- · 2020-04-20 08:51

First, if you want to preserve multiple selection, you have to remember your selected ones in an array since it would get lost if a cell gets recycled and reused. For that use something like a [IndexPath] type). If one selected cell is enough, you could use a non-array version of below code.

var selectedItems: [IndexPath] = []

Then, do your recoloring in your cell's cellForItemAt(:):

cell.backgroundColor = selectedItems.contains(indexPath) ? .red : .white

Your didSelectItemAt delegate function should look like:

if !selectedItems.contains(indexPath) { selectedItems.append(indexPath)}

collectionView.cellForItem(at: indexPath)?.backgroundColor = .red

and your didDeselectItemAt delegate function:

if let index = selectedItems.firstIndex(of: indexPath) { selectedItems.remove(at: index) }

collectionView.cellForItem(at: indexPath)?.backgroundColor = .white

This should actually work. Let me know if we have to do adjustments.

查看更多
一夜七次
3楼-- · 2020-04-20 09:07

Don't forget that UICollectionView has embedded reusing mechanism, so you should deselect your cells in the method "prepareToReuse" directly inside the cell class.

查看更多
We Are One
4楼-- · 2020-04-20 09:10

Take a class-level variable, say index

var index = -1

As you have said that multiple selections are not allowed so the following will do the job for you

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    index = indexPath.item
    collectionView.reloadData()
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    if let cell = cell {
        cell.backgroundColor = indexPath.item == index ? .red :  .white
    }
}

Whenever user tap on any cell we save the position in index variable and then call the reloadData() to notify collectionView about the change In cellForRowAt we check if the current cell us selected we set the color to red otherwise white

查看更多
登录 后发表回答