美文网首页
使用 CollectionView 实现瀑布式首页

使用 CollectionView 实现瀑布式首页

作者: yww | 来源:发表于2017-08-21 15:18 被阅读39次

首页在展示大量图片的时候, 如果内容尺寸不一致, 除了直接裁剪图片, 还可以使用瀑布式布局, 看起来也很美观.
例如花瓣网


花瓣网

我们也可以使用 CollectionView 实现类似的效果.
如图所示

demo

CollectionView

相较之下, 很多同学可能对 CollectionView 比较陌生, 其实想对于常用的 TableView, CollectionView 就只是多了一个布局, 你完全可以用 CollectionView 加上一个布局文件模拟出一个 TableView 的效果

布局类

布局类需要继承自UICollectionViewLayout, 并实现
这几个方法

  • prepare
  • layoutAttributesForElements:in
  • collectionViewContentSize

prepare 方法中, 我们在这里准备好了每个元素的布局, 然后在layoutAttributesForElements:in 中返回对应区域的布局信息. collectionViewContentSize 用于获取内容尺寸, 类似于ScrollViewContentSize

准备布局

每一列的列数目, 需要定下来, 我们这里为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

相关文章

网友评论

      本文标题:使用 CollectionView 实现瀑布式首页

      本文链接:https://www.haomeiwen.com/subject/ooicdxtx.html