如何访问自定义 CollectionView 单元格的初始化程序?

Posted

技术标签:

【中文标题】如何访问自定义 CollectionView 单元格的初始化程序?【英文标题】:How to access initializer for a custom CollectionView cell? 【发布时间】:2018-06-15 00:18:07 【问题描述】:

我有一个包含多个单元格的 collectionView。每个单元格都属于此类:

class OuterCollectionViewCell: UICollectionViewCell 

    @IBOutlet weak var stackView: UIStackView!

    override init(frame: CGRect) 
        super.init(frame: frame)
        print("initting")
        for i in 1...30 
            let view = UIView()
            view.backgroundColor = UIColor.red
            view.tag = i

            self.stackView.addSubview(view)
        
    
    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
    


我正在创建每个单元格,我希望像这样调用它的初始化程序:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "outerCell", for: indexPath) as! OuterCollectionViewCell
    cell.backgroundColor = UIColor.gray
    return cell

我的意图是向这个水平 stackView 添加 30 个子视图,以便显示 30 个条纹。我想在 init 中以编程方式添加这些子视图,以避免在情节提要中手动执行。但是现在没有调用 init 并且没有添加视图。知道为什么会这样以及如何做到这一点吗?

【问题讨论】:

【参考方案1】:

我希望这样称呼它的初始化器

您可以希望,但是,正如您正确地发现的那样,您注定要失望。通过调用dequeue 生成的单元格永远不会调用其init(frame:)

一个明显的解决方案是在cellForItemAt 中添加您的 30 个子视图。如果您这样做,您还需要包含一个测试,以确保在下次重用单元格时不会再次添加它们。换句话说,只有当它们不存在时才添加它们。

更简单:既然您已经实现了init(coder:),为什么不将您的 30-subviews 代码移到其中呢?这是一个初始化器,在通过出队创建单元格时调用,而不会在仅重用单元格时(显然)被调用。

但是,请注意,您正在做的事情还有其他问题。正如您的代码所代表的那样,您的视图没有大小,而且堆栈视图将如何构成还远不清楚。此外,仅仅说addSubview 不会导致堆栈视图对您的视图进行任何操作。所以基本上即使你的代码运行,我希望你实际上什么也看不到。但是,让我们一次过一座桥。

【讨论】:

谢谢!这正是我需要的反馈类型。因此,如果我将逻辑添加到所需的 init?(coder aDecoder: NSCoder) 中添加 30 个子视图,并且我给它们适当的大小 - 我会在布局约束的情况下这样做吗?请注意,现在我在 stackView 上使用同样的填充。另外,我打算有选择地为子视图着色,从而基本上创建条纹。最终将有 30 条条纹,每个条纹为一个月中的一天。月份由 collectionViewCell 表示。 请一次解决一个问题!您的问题只是让您的代码在单元创建时运行。这就是我回答的问题,你应该通过实验来确认它是正确的。我的最后一段并不是要打开一个全新的蠕虫罐头,而是要警告您,即使在您的代码运行之后,它实际上仍然无法正常工作。如果您想在代码运行后询问有关如何配置这些子视图的问题,请将其作为单独的问题提出!【参考方案2】:

这里的另一个潜在问题是如果您想将自定义方法变量添加到您的初始化程序。对于造型之类的事情......

我最终将所有布局代码提取到它自己的方法中,该方法在dequeueReusableCell 之后被调用。

let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
cell.ifNeeded(layout: .someStyle)

然后拥有一个自定义变量,您可以跟踪初始化。

var layout:Layout?

如果已经布局,则退出。

func ifNeeded(layout:Layout) 
    //exit if already laid out
    guard self.layout == nil else  return 
    self.layout = layout

【讨论】:

以上是关于如何访问自定义 CollectionView 单元格的初始化程序?的主要内容,如果未能解决你的问题,请参考以下文章

使用自定义 collectionView 布局更改单元格大小时如何使用 ScrollToItem(at:)

如何在collectionView自定义布局中的其他补充标题单元格上方添加标题补充单元格

如何在 swift ios 的自定义 collectionView 单元中将字符串值显示到多个标签?

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

如何自定义CollectionView中每个元素的大小和间距

UICollectionView 自定义单元格访问单元格外的属性