想必大家工作中或多或少会遇到下图样式的UI需求吧
像这种cell长度不固定,以此向右对齐排列的样式UI可以说是很常见的
一般的实现可能主要是分一下两种:
我们这里实现主要采用第二种方式,实现的方式是自定义一个UICollectionViewFlowLayout的子类,在这个类里对cell布局进行排列
主要代码如下:
/// main method for layout cell
/// - Parameter indexPath: indexpath
/// - Returns: layouted UICollectionViewLayoutAttributes
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
if let attr = calculatedAttrs[indexPath] { return attr }
guard let curAttr = super.layoutAttributesForItem(at: indexPath) else { return nil }
if isHorizontal {
// 如果滚动方向是水平的话,就直接返回。这里的水平布局主要适合不换行的那种
calculatedAttrs[indexPath] = curAttr
return curAttr
}
// 下面主要针对滚动方式是垂直方向的进行布局,因为实际开发中,绝大部分情况也是垂直滚动方向
let sectionInset = calculateSectionInsetForItem(at: indexPath.section)
let layoutWidth = collectionView?.frame.width ?? 0 - sectionInset.left - sectionInset.right
if indexPath.item == 0 {
// 如果是当前section的第一个元素,就直接设置x为sectionInset.left
curAttr.frame.origin.x = sectionInset.left
calculatedAttrs[indexPath] = curAttr
return curAttr
}
// 计算非第一个元素的frame布局
let prevIP = IndexPath(item: indexPath.item - 1, section: indexPath.section)
let prevRect = layoutAttributesForItem(at: prevIP)?.frame ?? .zero
let prevRectRightPoint = prevRect.origin.x + prevRect.size.width
let stretchedCurRect = CGRect(x: sectionInset.left,
y: curAttr.frame.origin.y,
width: layoutWidth,
height: curAttr.frame.size.height)
if !prevRect.intersects(stretchedCurRect) {
curAttr.frame.origin.x = sectionInset.left
calculatedAttrs[indexPath] = curAttr
return curAttr
}
curAttr.frame.origin.x = prevRectRightPoint + calculateMinimumInteritemSpacingForSection(at: indexPath.section)
calculatedAttrs[indexPath] = curAttr
return curAttr
}
/// 用字典存储已经计算过的cell item,常见的以空间换时间方式
private lazy var calculatedAttrs = [IndexPath: UICollectionViewLayoutAttributes]()
private lazy var collectionView: UICollectionView = {
// instance ZLCollectionLeftAlignLayout
let defaultLayout = ZLCollectionLeftLayout()
defaultLayout.minimumLineSpacing = 10.0
defaultLayout.minimumInteritemSpacing = 10.0
defaultLayout.scrollDirection = .vertical
defaultLayout.sectionInset = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 20.0, right: 10.0)
// set collectionViewLayout to a instance of ZLCollectionLeftLayout
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: defaultLayout)
collectionView.backgroundColor = .magenta
collectionView.showsVerticalScrollIndicator = false
return collectionView
}()
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let w = CGFloat.random(in: 20.0 ... 50.0)
return CGSize(width: 30.0 + w, height: 25.0)
}
代码开源到github上了,可以直接拿来使用