自动调整单元格大小:使单元格宽度等于集合视图

8

我正在使用自动调整单元格和自动布局以及集合视图相关技术。

我可以在代码中指定单元格初始化时的约束:

  func configureCell() {
    snp.makeConstraints { (make) in
      make.width.equalToSuperview()
    }
  }

然而,由于单元格尚未添加到collectionView中,因此应用程序会崩溃。
问题:
1.在单元格生命周期的哪个阶段可以使用cellwidth添加约束条件?
2.是否有默认方法可以使cellwidth等于collectionViewwidth,而无需访问UIScreenUIWindow的实例?
编辑: 该问题不是重复的,因为它不涉及如何使用自动缩放单元格功能,而是关于在使用自动布局时,在单元格生命周期的哪个阶段应用约束以实现所需结果。

可能是 UICollectionView Self Sizing Cells with Auto Layout 的重复问题。 - Oliver Atkinson
1
@OliverAtkinson 不是重复,请看编辑说明。 - Richard Topchii
2个回答

39
为了实现自适应大小的集合视图单元格,您需要执行两个操作:
  1. UICollectionViewFlowLayout 上指定 estimatedItemSize
  2. 在您的单元格上实现 preferredLayoutAttributesFitting(_:)

1. 在 UICollectionViewFlowLayout 上指定 estimatedItemSize

此属性的默认值为 CGSizeZero。将其设置为其他值会导致集合视图使用单元格的 preferredLayoutAttributesFitting(_:) 方法查询每个单元格的实际大小。如果您的所有单元格高度相同,请改用 itemSize 属性来指定单元格大小。

这只是一个估计值,用于计算滚动视图的内容大小,请将其设置为合理的值。

let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.estimatedItemSize = CGSize(width: collectionView.frame.width, height: 100)

2. 在您的UICollectionViewCell子类中实现preferredLayoutAttributesFitting(_:)

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)

    // Specify you want _full width_
    let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)

    // Calculate the size (height) using Auto Layout
    let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow)
    let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)

    // Assign the new size to the layout attributes
    autoLayoutAttributes.frame = autoLayoutFrame
    return autoLayoutAttributes
}

2
谢谢你的回答,我还没有实现第二部分。使用这种方法,多任务处理应该可以正常工作,而且不需要使用虚拟单元格的方法。我已经更新了你的答案以匹配最新的Swift语法。 - Richard Topchii
这适用于布局,但我无法在不使用委托sizeForItem方法的情况下干净地执行插入、删除和单元格扩展动画。如果有人有一个干净的解决方案,我很想知道。同时,我在这里提供了我的各种尝试示例:https://github.com/chrisco314/CollectionView-AutoLayout。它在第三个选项卡上使用sizeForItem方法可以干净地工作... - Chris Conover
嘿,Oliver 感谢您的发布。这个工作就像魔法一样。 - Anand
如果我的单元格大小不同怎么办?为什么必须设置estimatedItemSize - Vyachaslav Gerchicov
estimatedItemSize是一个猜测,以使滚动条正常工作,必须设置它以允许集合视图执行其余的计算。 - Oliver Atkinson

-1

你需要实现sizeForItemAt:来计算大小。

如果你的单元格高度不固定,我们还使用了“调整大小的单元格”。例如:

class MyFancyCell: UICollectionViewCell {
    class func cellSize(_ content: SomeContent, withWidth width: CGFloat) -> CGSize {
        sizingCell.content = content
        sizingCell.updateCellLayout(width)
        return sizingCell.systemLayoutSizeFitting(UILayoutFittingExpandedSize)
    }

    fileprivate static let sizingCell = Bundle.main.loadNibNamed("ContentCell", owner: nil, options: nil)!.first as! ContentCell    

    func updateCellLayout(width: CGFloat) {
        //Set constraints and calculate size    
    }
}

这不是自动调整单元格大小的功能。我熟悉这种方法。虽然它可以完美地工作,但看起来有点像黑客技巧。 - Richard Topchii

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接