首页在展示大量图片的时候, 如果内容尺寸不一致, 除了直接裁剪图片, 还可以使用瀑布式布局, 看起来也很美观.
例如花瓣网
我们也可以使用 CollectionView 实现类似的效果.
如图所示
CollectionView
相较之下, 很多同学可能对 CollectionView 比较陌生, 其实想对于常用的 TableView, CollectionView 就只是多了一个布局, 你完全可以用 CollectionView 加上一个布局文件模拟出一个 TableView 的效果
布局类
布局类需要继承自UICollectionViewLayout, 并实现
这几个方法
prepare
layoutAttributesForElements:in
collectionViewContentSize
prepare
方法中, 我们在这里准备好了每个元素的布局, 然后在layoutAttributesForElements:in
中返回对应区域的布局信息. collectionViewContentSize
用于获取内容尺寸, 类似于ScrollView
的 ContentSize
准备布局
每一列的列数目, 需要定下来, 我们这里为3列.
瀑布式布局, 其实就是所有元素一个一个挨着放下来就行了.
代码如下
override func prepare() {
self.layoutInfo.removeAll()
self.contentHeight = 0
let width = (self.collectionView!.frame.size.width - (self.columnsCount + 1) * self.space) / self.columnsCount
var currentY: [CGFloat] = [self.space, self.space, self.space]
for section in 0 ..< self.collectionView!.numberOfSections {
for item in 0 ..< self.collectionView!.numberOfItems(inSection: section) {
let indexPath = IndexPath(item: item, section: section)
let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
var column = 0
var minY = currentY[0]
for i in 0 ..< currentY.count {
if minY > currentY[i] {
minY = currentY[i]
column = i
}
}
let x = self.space + CGFloat(column) * (self.space + width)
let y = currentY[column]
let height = self.delegate.heightFor(itemAtIndexPath: indexPath, withWidth: width)
attribute.frame = CGRect(x: x, y: y, width: width, height: height)
self.layoutInfo[indexPath] = attribute
currentY[column] += height + self.space
self.contentHeight = max(currentY[column], self.contentHeight)
}
}
}
这里使用了一个layoutInfo
字典用来存放每个元素的布局信息.
self.space
表示了元素之前的间隙, self.contentHeight
则用来存放内容高度
获取对应区域布局信息
当某块区域需要显示的时候, 会调用layoutAttributesForElements:in
来获取对应区域的布局.
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var attributes = [UICollectionViewLayoutAttributes]()
for (_, attribute) in self.layoutInfo {
if attribute.frame.intersects(rect) {
attributes.append(attribute)
}
}
return attributes
}
获取内容高度
由于我们之前在准备的时候, 已经计算好了内容高度, 这里直接使用就可以了
override var collectionViewContentSize: CGSize {
return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight)
}
这样就大功告成了. demo可以点这里https://github.com/ywwzwb/CollectionViewDemo