
话不多说,来码
一、HomeWaterFallsCollectionLayout:
import UIKit
protocol PinterestLayoutDelegate: AnyObject {
func collectionView(_ collectionView: UICollectionView, calculateHeightAtIndexPath indexPath: IndexPath) -> CGFloat
/// header高度(默认为0)
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize
/// footer高度(默认为0)
func referenceSizeForFooter(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize
}
class HomeWaterFallsCollectionLayout: UICollectionViewFlowLayout{
var isExpand: Bool = false
weak var delegate: PinterestLayoutDelegate?
//默认列数
private(set) var ColumnCountDefault: Int = 2
//垂直间隔
private(set) var lineSpacing: CGFloat = 16.0
//水平间隔
private(set) var itemSpacing: CGFloat = 10.0
//边缘间隔
private(set) var EdgInsetsDefault = UIEdgeInsetsMake(10, 10, 10, 10)
//存放所有item的布局属性
lazy var attributesArray = [UICollectionViewLayoutAttributes]()
//存放所有列的当前高度
lazy var columnHeightsArray = [CGFloat]()
private var headerSize: CGSize = .zero
private var footerSize: CGSize = .zero
//collectionView的Content的高度
private var contentHeight: CGFloat = 0
//初始化
override func prepare() {
super.prepare()
//清除高度
self.contentHeight = 0
self.headerSize = .zero
self.footerSize = .zero
columnHeightsArray.removeAll()
attributesArray.removeAll()
// 开始创建每一个item对应的布局属性
let sectionCount: Int = self.collectionView!.numberOfSections
//添加每一个item的大小位置
for num in 0 ..< sectionCount {
let indexPath = IndexPath(item: 0, section: num)
//添加header
let headerAttri = self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionHeader, at: indexPath)
if let header = headerAttri {
self.attributesArray.append(header)
self.columnHeightsArray.removeAll()
}
//初始化y值
let itemCount = self.collectionView!.numberOfItems(inSection: num)
for _ in 0 ..< itemCount {
columnHeightsArray.append(self.contentHeight)
}
//添加item
for i in 0 ..< itemCount {
let indexPat = IndexPath(item: i, section: num)
let attrs = self.layoutAttributesForItem(at: indexPat)
if let attri = attrs {
attributesArray.append(attri)
}
}
//添加footer
let footerAttributes = self.layoutAttributesForSupplementaryView(ofKind: UICollectionElementKindSectionFooter, at: indexPath)
if let footer = footerAttributes {
self.attributesArray.append(footer)
}
}
}
//返回indexPath位置上每一个元素的布局属性
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = UICollectionViewLayoutAttributes.init(forCellWith: indexPath)
let collectionWidth = self.collectionView?.frame.size.width
//item的宽度
let itemsWidth = (collectionWidth! - EdgInsetsDefault.left - EdgInsetsDefault.right - CGFloat(ColumnCountDefault - 1) * itemSpacing ) / CGFloat(ColumnCountDefault)
//item的高度(通过代理获得文案的动态高度)
let delegateHeight = delegate?.collectionView(collectionView!, calculateHeightAtIndexPath: indexPath) ?? 0
let itemsHeight = itemsWidth + delegateHeight
//高度最短的序列号
var minColum: Int = 0
//高度最短的列的高度
var minHeight = columnHeightsArray[0]
//历遍所有高度取出最短列的高度和序列号
for i in 1 ..< ColumnCountDefault {
let columnH = columnHeightsArray[i]
if minHeight > columnH {
minHeight = columnH
minColum = i
}
}
//设置每一个item的x、y点
let x = EdgInsetsDefault.left + CGFloat(minColum) * (itemsWidth + itemSpacing)
var y = minHeight
//如果不是第一个,则需要加上间隔
if y != self.EdgInsetsDefault.top {
y += lineSpacing
}
attrs.frame = CGRect(x: x, y: y, width: itemsWidth, height: CGFloat(itemsHeight))
//更新数组中最短列的高度
columnHeightsArray[minColum] = attrs.frame.maxY
if self.contentHeight < minHeight {
self.contentHeight = minHeight
}
//取最大的高度,即下一个section与当前section的距离
for i in 0..<self.columnHeightsArray.count {
if self.contentHeight < self.columnHeightsArray[i] {
self.contentHeight = self.columnHeightsArray[i]
}
}
return attrs
}
//设置headerView、footerView的布局属性
override func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attri = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath)
if elementKind == UICollectionElementKindSectionHeader {
if let headerSize = self.delegate?.referenceSizeForHeader(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.headerSize = headerSize
}
attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.headerSize.width, height: self.headerSize.height)
self.contentHeight += self.headerSize.height
}else if elementKind == UICollectionElementKindSectionFooter{
if let footer = self.delegate?.referenceSizeForFooter(collectionView: self.collectionView!, layout: self, section: indexPath.section) {
self.footerSize = footer
}
attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.footerSize.width, height: self.footerSize.height)
self.contentHeight += self.footerSize.height
}
return attri
}
//返回rect范围内所有元素的布局属性的数组,即collection的item的frame
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attributesArray
}
//返回所有列的高度,即collectionView的滚动范围
override var collectionViewContentSize: CGSize{
return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight)
}
}
二、应用HomeWaterFallsView:
2.1写个collectionview:
let layout = HomeWaterFallsCollectionLayout()
layout.delegate = self
let new = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
new.dataSource = self
new.backgroundColor = #colorLiteral(red: 0.6644982952, green: 0.9803921569, blue: 0.8418341308, alpha: 1)
new.register(HomeWaterFallsCollectionCell.self, forCellWithReuseIdentifier: "HomeWaterFallsCollectionCell")
new.register(HomeWaterFallsVipView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: HomeWaterFallsVipView.header)
new.register(HomeWaterFallsFooterView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: HomeWaterFallsFooterView.footer)
return new
}()
2.2设置cell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let ranList = self.vm!.randomList
let firstList = Array(ranList.prefix(4))
let lastList = Array(ranList.dropFirst(4))
switch indexPath.section {
case 0:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeWaterFallsCollectionCell", for: indexPath) as! HomeWaterFallsCollectionCell
let user = firstList[indexPath.row]
cell.configData(user)
return cell
default:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "HomeWaterFallsCollectionCell", for: indexPath) as! HomeWaterFallsCollectionCell
let user = lastList[indexPath.row]
cell.configData(user)
return cell
}
}
2.3设置header、footer
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionElementKindSectionHeader {
let footView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HomeWaterFallsVipView.header, for: indexPath) as! HomeWaterFallsVipView
return footView
}else if kind == UICollectionElementKindSectionFooter{
let footView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HomeWaterFallsFooterView.footer, for: indexPath) as! HomeWaterFallsFooterView
if indexPath.section == 0 {
footView.titleLable.text = "暂无更多数据,下面为你展示随机用户"
}else if indexPath.section == 1{
footView.titleLable.text = "数据已加载完成"
}
return footView
}else{
return UICollectionReusableView()
}
}
2.4、传递高度宽度给layout:具体高度根据自己的业务需求传递,不需要的传0
extension HomeWaterFallsView: PinterestLayoutDelegate{
//设置headerView高度
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize {
return CGSize(width: kScreenWidth, height: kScreenWidth/3 + 70 + 16)
}
//设置footerView高度(显示隐藏height给0即可)
func referenceSizeForFooter(collectionView collection: UICollectionView, layout: HomeWaterFallsCollectionLayout, section: Int) -> CGSize {
var height: CGFloat = 0
switch section {
case 0:
return CGSize(width: kScreenWidth, height: 60)
case 1:
height = self.vm?.hasNext == false ? 60:0
return CGSize(width: kScreenWidth, height: height)
default:
return CGSize(width: kScreenWidth, height: height)
}
}
//用来设置item的高度(计算文案的高度,然后通过delegate传给itemsHeight),不需要的传0
func collectionView(_ collectionView: UICollectionView, calculateHeightAtIndexPath indexPath: IndexPath) -> CGFloat {
let ranList = self.vm!.randomList
let firstList = Array(ranList.prefix(4))//取前面4个数组放在第一个section
let lastList = Array(ranList.dropFirst(4))//剩余的数组放在第二个section
switch indexPath.section {
case 0:
return firstList[indexPath.row].resume?.pdesc?.getLabelHeight(constraintedWidth: kScreenWidth/2 - 40, font: UIFont.systemFont(ofSize: 14)) ?? 0
default:
return lastList[indexPath.row].resume?.pdesc?.getLabelHeight(constraintedWidth: kScreenWidth/2 - 40, font: UIFont.systemFont(ofSize: 14)) ?? 0
}
}
}
四、友情练字:163咳5137659,如果对你有帮助,请当面赏我一大嘴巴子,蟹蟹
网友评论