user3431800
user3431800

Reputation: 301

collectionView cells randomly gets highlighted after reloadData()

I am practicing to use collectionView to build a calendar.

My implementation is quit simple right now, mainly a copy of https://github.com/Akhilendra/calenderAppiOS/tree/master/myCalender2, just image a simple calendar. enter image description here

I am trying to make some advancements on it by letting users select the date they want and create a little border after the cell is selected.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CustomCell
    cell.backgroundColor=UIColor.clear
    if indexPath.item <= firstWeekDayOfMonth - 2 {
        print(firstWeekDayOfMonth)
        cell.isHidden=true
    } else {

        let calcDate = indexPath.row-firstWeekDayOfMonth+2
        cell.isHidden=false
        cell.dateLabel.text="\(calcDate)"
        if calcDate < todaysDate && currentYear == presentYear && currentMonthIndex == presentMonthIndex {
            cell.isUserInteractionEnabled=true
            cell.dateLabel.textColor = UIColor.darkGray
        } else {
            cell.isUserInteractionEnabled=true
            cell.dateLabel.textColor = UIColor.black
        }
    }
    return cell
}

 func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    addToList.append(indexPath)
    //dayCollectionView.deselectItem(at: indexPath, animated: true)
    let cell = collectionView.cellForItem(at: indexPath)
    cell?.layer.borderWidth = 2.0
    cell?.layer.borderColor = UIColor.gray.cgColor
}

The issue right now is the selected cells will jump all around my collectionView because the reuse feature. I've done some research that the way to fix this is to avoid using reloadData, but i need to flush my whole collectionView when i am forwarding to the next month.

Can someone help me out with this situation? I want to clear out the selected cells once the user move to the next month and maintain the selected cells on the month that the user did the selections.

Thank you in advance!

Upvotes: 2

Views: 1008

Answers (1)

Sandeep Bhandari
Sandeep Bhandari

Reputation: 20379

Problem:

The reason cell gets randomly highlighted in your collectionView is because cell gets reused in CollectionView and TableView. When a user selects the cell you highlight the cell by changing its border width and border color but when user scrolls the same cell gets reused for some other indexPath and because you havent removed the applied effects when cell gets reused cell appears highlighted at wrong position.

Solution :

Because you have a custom cell class of your own, you can always use prepareForReuse to clear the effect applied to cell when cell gets reused.

So open up your CustomCell class and add

override func prepareForReuse() {
    super.prepareForReuse()
    self.layer.borderWidth = 1.0 //whatever the default border width is
    self.layer.borderColor = UIColor.clear.cgColor //whatever the cell's default color is
}

But this solves only half your problem, now though unwanted cell's will not highlight when user scrolls back to selected cell even the selected cell will not be highlighted any longer. For that to happen you need to conditionally highlight cell if it needs to be highlighted in cellForRowAtIndexPath

So modify your cellForRowAtIndexPath as

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! CustomCell
    cell.backgroundColor=UIColor.clear
    if indexPath.item <= firstWeekDayOfMonth - 2 {
        print(firstWeekDayOfMonth)
        cell.isHidden=true
    } else {
        let calcDate = indexPath.row-firstWeekDayOfMonth+2
        cell.isHidden=false
        cell.dateLabel.text="\(calcDate)"
        if calcDate < todaysDate && currentYear == presentYear && currentMonthIndex == presentMonthIndex {
            cell.isUserInteractionEnabled=true
            cell.dateLabel.textColor = UIColor.darkGray
        } else {
            cell.isUserInteractionEnabled=true
            cell.dateLabel.textColor = UIColor.black
        }

        //check if cell needs to be highlighted
        //else condition isnt required because we have prepareForReuse in place
        if addToList.contains(indexPath) {
            cell?.layer.borderWidth = 2.0
            cell?.layer.borderColor = UIColor.gray.cgColor
        }
    }
    return cell
}

In the code above else condition isn't required because we have prepareForReuse in place and it does the job of removing all the highlights added to cell.

Hope it helps :)

Upvotes: 2

Related Questions