Search code examples
swiftxcodeuicollectionviewuicollectionviewcellnsindexpath

Swift CollectionViewCells Issue


Sorry for the vague title but I wasn't completely sure was to call it. I have a list of collection view cells in a collectionview these cells just have a white background. I have a total of 20 cells and I want the first one to have a cyan background and the fourth to have a green background. My issue is that if the list is big enough and I scroll the colors seem to be random sometimes 4 green and 2 cyan at the top instead of just 1 cyan and 1 green. I think this is due to using index path.row in the func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell method and assigning colors based on indexpath.row. I think index path.row changes as I scroll so when I scroll to the bottom index path.row is the item at the top of the screen not the top of the list. I understand this is not the proper way to achieve this, is there anyway to get the first/last item from the list instead of the first/last currently on my screen? Is there a better way to go about this entirely?

Here is a quick example of what the issue looks like - https://gyazo.com/e66d450e9ac50b1c9acd521c959dd067

EDIT:

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int` is return 20 and in `func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell` this is what I have - `let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Invite Cell", for: indexPath) as! InviteCell
    print(indexPath.row)

    if indexPath.row == 0 {
        cell.InviteCellContainer.backgroundColor = UIColor.cyan
    } else if indexPath.row == 5 {
        cell.InviteCellContainer.backgroundColor = UIColor.green
    }
    return cell
}

Solution

  • Cells are reused. Make sure that any UI element has a defined state in cellForItemAt:

    In your code the state is undefined if the row is not 0 and not 5. So you need to add a case for all other indexes:

    if indexPath.row == 0 {
        cell.InviteCellContainer.backgroundColor = UIColor.cyan
    } else if indexPath.row == 5 {
        cell.InviteCellContainer.backgroundColor = UIColor.green
    } else {
        cell.InviteCellContainer.backgroundColor = UIColor.gray // or what the default color is
    }
    return cell
    

    A more descriptive syntax is a switch expression

    switch indexPath.row {
        case 0: cell.InviteCellContainer.backgroundColor = UIColor.cyan
        case 4: cell.InviteCellContainer.backgroundColor = UIColor.green
        default: cell.InviteCellContainer.backgroundColor = UIColor.gray
    }