Reputation: 301
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.
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
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