I have a collectionView that represents a span of time. Each cell is a month. In each cell there is a horizontal stack view where each view represents a day.
The full project is here if you wanna try it out: https://github.com/AlexMarshall12/iOS-timeline
In my ViewController, I generate a random array of dates. Each time a cell is called in cellForItemAt, a custom function finds the dates in the array which are in the cell month.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MonthCollectionViewCell", for: indexPath) as! MonthCollectionViewCell
cell.backgroundColor = UIColor.gray
let firstDate = dates.first
let index = indexPath.item
let monthDate = Calendar.current.date(byAdding: .month, value: index, to: firstDate as! Date)
let monthInt = Calendar.current.component(.month, from: monthDate!)
let yearInt = Calendar.current.component(.year, from: monthDate!)
cell.monthLabel.text = String(monthInt)+" "+String(yearInt)
cell.year = yearInt
cell.month = monthInt
let monthDates = dates(self.dates as! [Date], withinMonth: monthInt, withinYear: yearInt)
cell.colorViews(monthDates:monthDates)
return cell
}
func dates(_ dates: [Date], withinMonth month: Int, withinYear year: Int) -> [Date] {
let calendar = Calendar.current
let components: Set<Calendar.Component> = [.month,.year]
let filtered = dates.filter { (date) -> Bool in
let monthAndYear = calendar.dateComponents(components, from: date)
return (monthAndYear.month == month && monthAndYear.year == year)
}
return filtered
}
These are passed to the custom cell class and it finds the subviews which represent those days and colors them like so:
class MonthCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var monthLabel: UILabel!
@IBOutlet weak var stackView: UIStackView!
var year: Int?
var month: Int?
override func awakeFromNib() {
super.awakeFromNib()
for _ in 0...30 { //for the 31 days in a month...
let tick = UIView()
self.stackView?.addArrangedSubview(tick)
}
}
func colorViews(monthDates: [Date]){
for date in monthDates {
let dayIndex = Calendar.current.component(.day, from: date)
let tick = stackView.arrangedSubviews[dayIndex]
tick.backgroundColor = UIColor.red
}
}
}
I believe this should give me the desired affect. For instance if there are 3 dates generated across 2 years, it would create 3 stripes across 2 years worth of month cells. However, I find that many more than 3 stripes are rendered, almost like its duplicating the subview across many cells.
Here is what it looks like now: https://imgur.com/a/ZNSmIS8. Note this was with 3 dates. 5 stripes appear. It seems that scrolling back and forth adds stripes as though cellForItemAt is being called on the wrong cell? Im not exactly sure.
Any advice on what I am doing wrong in this implementation would be awesome.
Edit: I have added this method to my custom cell class:
override func prepareForReuse() {
super.prepareForReuse()
for each_view in self.subviews {
print("Cleared!")
each_view.backgroundColor = UIColor.clear
}
}
The same issue is still occurring especially with a really long time range and/or fast scrolling