android 九宫格 瀑布流,Swift实现UICollectionView支持多 section 场景下瀑布流、线性排列、九宫格样式...

通过UICollectionViewLayout实现瀑布流

代码如下

@objc protocol WaterfallFlowLayoutDelegate: NSObjectProtocol {

// 必选delegate实现

/// collectionItem高度

func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat

// 可选delegate实现

/// 每个section 列数(默认2列)

@objc optional func columnNumber(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> Int

/// header高度(默认为0)

@objc optional func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> CGSize

/// footer高度(默认为0)

@objc optional func referenceSizeForFooter(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> CGSize

/// 每个section 边距(默认为0)

@objc optional func insetForSection(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> UIEdgeInsets

/// 每个section item上下间距(默认为0)

@objc optional func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> CGFloat

/// 每个section item左右间距(默认为0)

@objc optional func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> CGFloat

/// section头部header与上个section尾部footer间距(默认为0)

@objc optional func spacingWithLastSection(collectionView collection: UICollectionView, layout: WaterfallFlowLayout, section: Int) -> CGFloat

}

class WaterfallFlowLayout: UICollectionViewLayout {

weak var delegate: WaterfallFlowLayoutDelegate?

private var sectionInsets: UIEdgeInsets = .zero

private var columnCount: Int = 2

private var lineSpacing: CGFloat = 0

private var interitemSpacing: CGFloat = 0

private var headerSize: CGSize = .zero

private var footerSize: CGSize = .zero

//存放attribute的数组

private var attrsArray: [UICollectionViewLayoutAttributes] = []

//存放每个section中各个列的最后一个高度

private var columnHeights: [CGFloat] = []

//collectionView的Content的高度

private var contentHeight: CGFloat = 0

//记录上个section高度最高一列的高度

private var lastContentHeight: CGFloat = 0

//每个section的header与上个section的footer距离

private var spacingWithLastSection: CGFloat = 0

override func prepare() {

super.prepare()

self.contentHeight = 0

self.lastContentHeight = 0

self.spacingWithLastSection = 0

self.lineSpacing = 0

self.sectionInsets = .zero

self.headerSize = .zero

self.footerSize = .zero

self.columnHeights.removeAll()

self.attrsArray.removeAll()

let sectionCount = self.collectionView!.numberOfSections

// 遍历section

for idx in 0..

let indexPath = IndexPath(item: 0, section: idx)

if let columnCount = self.delegate?.columnNumber?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.columnCount = columnCount

}

if let inset = self.delegate?.insetForSection?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.sectionInsets = inset

}

if let spacingLastSection = self.delegate?.spacingWithLastSection?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.spacingWithLastSection = spacingLastSection

}

// 生成header

let itemCount = self.collectionView!.numberOfItems(inSection: idx)

let headerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, at: indexPath)

if let header = headerAttri {

self.attrsArray.append(header)

self.columnHeights.removeAll()

}

self.lastContentHeight = self.contentHeight

// 初始化区 y值

for _ in 0..

self.columnHeights.append(self.contentHeight)

}

// 多少个item

for item in 0..

let indexPat = IndexPath(item: item, section: idx)

let attri = self.layoutAttributesForItem(at: indexPat)

if let attri = attri {

self.attrsArray.append(attri)

}

}

// 初始化footer

let footerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionView.elementKindSectionFooter, at: indexPath)

if let footer = footerAttri {

self.attrsArray.append(footer)

}

}

}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {

return self.attrsArray

}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

if let column = self.delegate?.columnNumber?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.columnCount = column

}

if let lineSpacing = self.delegate?.lineSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.lineSpacing = lineSpacing

}

if let interitem = self.delegate?.interitemSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.interitemSpacing = interitem

}

let attri = UICollectionViewLayoutAttributes(forCellWith: indexPath)

let weight = self.collectionView!.frame.size.width

let itemSpacing = CGFloat(self.columnCount - 1) * self.interitemSpacing

let allWeight = weight - self.sectionInsets.left - self.sectionInsets.right - itemSpacing

let cellWeight = allWeight / CGFloat(self.columnCount)

let cellHeight: CGFloat = (self.delegate?.heightForRowAtIndexPath(collectionView: self.collectionView!, layout: self, indexPath: indexPath, itemWidth: cellWeight))!

var tmpMinColumn = 0

var minColumnHeight = self.columnHeights[0]

for i in 0..

let columnH = self.columnHeights[i]

if minColumnHeight > columnH {

minColumnHeight = columnH

tmpMinColumn = i

}

}

let cellX = self.sectionInsets.left + CGFloat(tmpMinColumn) * (cellWeight + self.interitemSpacing)

var cellY: CGFloat = 0

cellY = minColumnHeight

if cellY != self.lastContentHeight {

cellY += self.lineSpacing

}

if self.contentHeight < minColumnHeight {

self.contentHeight = minColumnHeight

}

attri.frame = CGRect(x: cellX, y: cellY, width: cellWeight, height: cellHeight)

self.columnHeights[tmpMinColumn] = attri.frame.maxY

//取最大的

for i in 0..

if self.contentHeight < self.columnHeights[i] {

self.contentHeight = self.columnHeights[i]

}

}

return attri

}

override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {

let attri = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)

if elementKind == UICollectionView.elementKindSectionHeader {

if let headerSize = self.delegate?.referenceSizeForHeader?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.headerSize = headerSize

}

self.contentHeight += self.spacingWithLastSection

attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.headerSize.width, height: self.headerSize.height)

self.contentHeight += self.headerSize.height

self.contentHeight += self.sectionInsets.top

} else if elementKind == UICollectionView.elementKindSectionFooter {

if let footerSize = self.delegate?.referenceSizeForFooter?(collectionView: self.collectionView!, layout: self, section: indexPath.section) {

self.footerSize = footerSize

}

self.contentHeight += self.sectionInsets.bottom

attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.footerSize.width, height: self.footerSize.height)

self.contentHeight += self.footerSize.height

}

return attri

}

override var collectionViewContentSize: CGSize {

return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight)

}

}

调用如下

let layout = WaterfallFlowLayout()

layout.delegate = self

let collection = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值