子视图在 collectionView 单元格中重复?

Posted

技术标签:

【中文标题】子视图在 collectionView 单元格中重复?【英文标题】:SubViews being duplicated across collectionView cells? 【发布时间】:2018-06-18 22:59:12 【问题描述】:

我有一个代表时间跨度的 collectionView。每个单元格是一个月。在每个单元格中都有一个水平堆栈视图,其中每个视图代表一天。

如果你想尝试一下,完整的项目在这里:https://github.com/AlexMarshall12/ios-timeline

在我的 ViewController 中,我生成了一个随机的日期数组。每次在 cellForItemAt 中调用单元格时,自定义函数都会在数组中查找单元格月份中的日期。

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

这些被传递给自定义单元类,它会找到代表那些日子的子视图并将它们着色,如下所示:

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
        
    

我相信这应该会给我想要的效果。例如,如果在 2 年内生成 3 个日期,它将在 2 年的月单元格中创建 3 个条纹。但是,我发现渲染了超过 3 个条纹,几乎就像它在许多单元格中复制子视图一样。

这是它现在的样子:https://imgur.com/a/ZNSmIS8。请注意,这是 3 个日期。出现 5 条条纹。似乎来回滚动会添加条纹,就好像在错误的单元格上调用了 cellForItemAt?我不太确定。

任何关于我在这个实现中做错了什么的建议都会很棒。

编辑:我已将此方法添加到我的自定义单元格类中:

override func prepareForReuse() 
    super.prepareForReuse()
    for each_view in self.subviews 
        print("Cleared!")
        each_view.backgroundColor = UIColor.clear
    

同样的问题仍然存在,尤其是在很长的时间范围和/或快速滚动时

【问题讨论】:

【参考方案1】:

看起来您实际上并没有重置 dequeueReusableCell 返回给您的单元格的内容。

dequeueReusableCell 为您提供可能已被使用的单元格,以优化性能。方法说明的文档:

如果现有单元格可供重用,则此方法将调用该单元格的 prepareForReuse() 方法。

如果您查看documentation 的prepareForReuse(),您会发现您有机会重置单元格的属性,以便您可以重复使用单元格。

如果您重置单元格,您可能会发现它开始按您预期的方式运行。

【讨论】:

我明白了。查看我在编辑中添加的 prepareForReuse 函数。你是这么想的吗?不幸的是还是同样的问题 关闭!在您的实现中,您使用的是self.subviews,但实际上您的视图位于堆栈视图中。因此,如果您的 prepareForReuse 看起来像:for view in stackView.subviews view.backgroundColor = .clear 那应该可以工作

以上是关于子视图在 collectionView 单元格中重复?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 collectionView 单元格中设置 NSLayoutConstraint 常量?

如何在 swift 3 中的 tableview 单元格中添加带有自定义视图的 collectionView?

如何在 tvos 应用程序的 collectionview 单元格中的按钮上移动焦点?

从popover返回后如何在collectionview单元格中填充文本字段

如何更改集合视图单元格中的图像

UIButton 在 collectionView 单元格中不起作用