【发布时间】:2021-05-10 22:58:44
【问题描述】:
我想创建一个自定义 UICollectionView 能够根据其配置以不同的方式做出反应。
我创建了UICollectionViewFlowLayout 的自定义子类,并将其estimatedItemSize 设置为UICollectionViewFlowLayout.automaticSize。该组件还能够根据其配置计算不同的布局宽度。
ColumnFlowLayout.swift
import UIKit
class ColumnFlowLayout: UICollectionViewFlowLayout {
let columns: Int
init(columns: Int, insets: UIEdgeInsets) {
self.columns = columns
super.init()
self.sectionInsetReference = .fromContentInset
self.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
self.minimumInteritemSpacing = insets.top
self.minimumLineSpacing = insets.bottom
self.sectionInset = insets
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes]
layoutAttributesObjects?.forEach({ layoutAttributes in
if layoutAttributes.representedElementCategory == .cell {
if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame {
layoutAttributes.frame = newFrame
}
}
})
return layoutAttributesObjects
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
return nil
}
layoutAttributes.frame.size.width = self.estimatedWidth()
return layoutAttributes
}
private func estimatedWidth() -> CGFloat {
guard let collectionView = collectionView else { return 0.0 }
let marginsAndInsets = sectionInset.left + sectionInset.right + collectionView.safeAreaInsets.left + collectionView.safeAreaInsets.right + minimumInteritemSpacing * CGFloat(columns - 1)
return ((collectionView.bounds.size.width - marginsAndInsets) / CGFloat(columns)).rounded(.down)
}
}
然后我将它用于 UICollectionView 配置。
CollectionViewController.swift
private func prepareCollectionView() {
let columnLayout = ColumnFlowLayout(columns: Layout.COLUMNS, insets: Layout.INSETS)
self.collectionView!.collectionViewLayout = columnLayout
self.collectionView!.contentInsetAdjustmentBehavior = .always
...
}
为了使其工作,每个UICollectionViewCell 都有preferredLayoutAttributesFitting
BaseCollectionViewCell.swift
import UIKit
class BaseCollectionCell: UICollectionViewCell {
...
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
return layoutAttributes
}
...
}
输出接近预期的结果,除了顶部间距:
我希望像这样将每个单元格对齐在顶部:
你有什么建议吗?
【问题讨论】:
标签: ios swift uicollectionview autolayout uicollectionviewcell