您需要继承 UICollectionViewLayout 是正确的。
开始之前要了解的本质是,您至少需要计算集合视图中每个单元格的位置和大小。 UICollectionViewLayout 只是提供该信息的结构化方式。你得到了结构,但你必须自己提供其他一切。
您需要重写 4 个方法:
- 准备
- 无效布局
- layoutAttributesForItemAtIndexPath
- layoutAttributesForElementsInRect
一个技巧是将布局属性缓存在查找表(字典)中:
var cachedItemAttributes = [IndexPath: UICollectionViewLayoutAttributes]()
在prepare中,计算collectionView中每个indexPath的布局属性:
override func prepare() {
super.prepare()
calculateAttributes()
}
在 invalidateLayout 中重置缓存的布局属性并重新计算它们:
override func invalidateLayout() {
super.invalidateLayout()
cachedItemAttributes = [:]
calculateAttributes()
}
在 layoutAttributesForItemAtIndexPath 中,您使用查找表返回正确的布局属性:
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
return cachedItemAttributes[indexPath]
}
在 layoutAttributesForElementsInRect 中过滤查找表以查找指定矩形内的元素:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return cachedItemAttributes.filter { rect.intersects($0.value.frame) }.map { $0.value }
}
最后一块拼图是布局属性的实际计算。这里我只提供伪代码:
func calculateAttributes() {
// For each indexpath (you can get this from the collectionView property using numberOfSections and numberOfItems:inSection )
// calculate the frame, i.e the origin point and size of each cell in your collectionView and set it with UICollectionViewLayoutAttributes.frame
// There are many other properties on UICollectionViewLayoutAttributes that you can tweak for your layout, but frame is a good starting point from which you can start experimenting.
// Add the layout attributes to the lookup table
// end loop
}
回答你的问题,下面是计算每个单元格位置的伪代码:
// If width of cell + current width of row + spacing, insets and margins exceeds the available width
// move to next row.
// else
// cell origin.x = current width of row + interitem spacing
// cell origin.y = number of rows * (row height + spacing)
// endif
如果您需要可配置自定义布局,则在可用签名足够的情况下使用 UICollectionViewDelegateFlowLayout,或者定义您自己的继承自 UICollectionViewDelegateFlowLayout 或 UICollectionViewDelegate。因为您的协议继承自 UICollectionViewDelegateFlowLayout,而后者本身继承自 UICollectionViewDelegate,所以您可以直接将其设置为 viewcontroller 中的 collectionView 委托。在您的自定义集合视图布局中,您只需要将委托从 UICollectionViewDelegate 转换为您的自定义协议即可使用它。请记住处理转换失败或委托未实现协议方法的情况。