流式布局:不规则的瀑布流,主要通过继承UICollectionViewFlowLayout,自定义布局。
UICollectionViewFlowLayout
- prepareLayout()
- collectionViewContentSize()
- layoutAttributesForElementsInRect(_:)
- layoutAttributesForItem(at indexPath: IndexPath)
这几个方法或者属性是需要重写。从后往前详细了解这几个方法。其实是有一定的逻辑流程的。
流程
- 首先需要确定在indexPath位置的item的frame
- 其次告诉在区域范围内,显示所有item的布局信息。
- 告诉UIcollectionview滚动的区域范围
- 提前计算,所需要的布局属性.
可以逆向思维整个流程。先确定一个item的布局信息,然后所有item组成了区域内的布局,返回整个布局滚动的范围。
//内容宽度
let contentWidth = screenWidth
//内容高度
var contentHeight: CGFloat = 0
//列数
let numberOfColumns = 2
//存储布局属性数组,提高性能
var cache = [UICollectionViewLayoutAttributes]()
复制代码
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
//返回在具体item的位置信息。
return cache[indexPath.row]
}
复制代码
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
//返回在区域范围内,所有的布局信息
return cache
}
复制代码
override var collectionViewContentSize: CGSize {
//整个显示布局的区域
return CGSize(width: contentWidth, height: contentHeight)
}
复制代码
override func prepare() {
super.prepare()
//准备显示布局时候,提前计算item的布局属性,内容区域,并进行缓存。提高性能。
if cache.isEmpty {
// 2. Pre-Calculates the X Offset for every column and adds an array to increment the currently max Y Offset for each column
// 每列宽度
let columnWidth = contentWidth / CGFloat(numberOfColumns)
var xOffset = [CGFloat]()
// 其实就是xOffset就是两个,都是固定的.
for column in 0 ..< numberOfColumns {
xOffset.append(CGFloat(column) * columnWidth )
}
var column: Int = 0
var yOffset = [CGFloat](repeating: 0, count: numberOfColumns)
// 3. Iterates through the list of items in the first section
for item in 0 ..< collectionView!.numberOfItems(inSection: 0) {
let indexPath = NSIndexPath(item: item, section: 0)
// 4. Asks the delegate for the height of the picture and the annotation and calculates the cell frame.
// 这个width是为了计算comment的长度的.
let randomNumber:Int = Int(arc4random() % 100) + 60
let height = CGFloat(randomNumber)
let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
// 5. Creates an UICollectionViewLayoutItem with the frame and add it to the cache
let attributes = UICollectionViewLayoutAttributes.init(forCellWith: indexPath as IndexPath)
attributes.frame = frame
cache.append(attributes)
// 6. Updates the collection view content height
contentHeight = max(contentHeight, frame.maxY)
yOffset[column] = yOffset[column] + height
column = column >= (numberOfColumns - 1) ? 0 : 1
}
}
}
复制代码
总结
核心是计算item所在位置的布局信息。
prepare()去缓存,提高性能。
引用 叶孤城:UICollectionView自定义布局教程——Pinterest - CocoaChina_让移动开发更简单
iOS开发进阶 - 自定义UICollectionViewLayout实现瀑布流布局 - W_C__L的博客 - CSDN博客