相信大家对UICollectionView的使用都不陌生了,这里我要简单说下瀑布流的功能实现,希望有助于大家对瀑布流的实现逻辑有所加深理解,先上效果图
效果图

WaterFallLayout 类
import Foundation
import UIKit
class WaterFallLayout: UICollectionViewFlowLayout {
// item个数
let itemCount: Int
// items的布局信息
var attributeArray: Array<UICollectionViewLayoutAttributes>?
// 实现必要的构造方法
required init?(coder: NSCoder) {
itemCount = 0
super.init(coder: coder)
}
// 自定义一个初始化构造方法
init(itemCount: Int) {
self.itemCount = itemCount
super.init()
}
// 准备方法
override func prepare() {
// 调用父类的准备方法
super.prepare()
// 设置为竖直布局
self.scrollDirection = .vertical
// 初始化数组
attributeArray = Array<UICollectionViewLayoutAttributes>()
// 先计算每个item的宽度,默认为两列布局
let WIDTH = (UIScreen.main.bounds.size.width - self.minimumInteritemSpacing) / 2
// 定义一个元组表示每一列的动态高度
var queueHeight:(one: Int, two: Int) = (0,0)
// 进行循环设置
for index in 0..<self.itemCount {
// 设置indexPath,默认一个分区
let indexPath = IndexPath(item: index, section: 0)
// 创建布局属性类
let attris = UICollectionViewLayoutAttributes(forCellWith: indexPath)
// 随机一个高度在80到90之间的值
let height: Int = Int(arc4random() % 110 + 80)
// 哪列高度小就把它放那列下面
// 标记那一列
var queue = 0
if queueHeight.one <= queueHeight.two {
queueHeight.one += (height + Int(self.minimumInteritemSpacing))
queue = 0
} else {
queueHeight.two += (height+Int(self.minimumInteritemSpacing))
queue = 1
}
// 设置item的位置
let tmpH = queue == 0 ? queueHeight.one-height : queueHeight.two-height
attris.frame = CGRect(x: (self.minimumInteritemSpacing+WIDTH)*CGFloat(queue), y: CGFloat(tmpH), width: WIDTH, height: CGFloat(height))
// 添加到数组中
attributeArray?.append(attris)
}
// 以最大一列的高度计算每个item高度的中间值,这样就可以保证滑动范围的正确
if queueHeight.one <= queueHeight.two {
self.itemSize = CGSize(width: WIDTH, height: CGFloat(queueHeight.two*2/self.itemCount)-self.minimumLineSpacing)
} else {
self.itemSize = CGSize(width: WIDTH, height: CGFloat(queueHeight.one*2/self.itemCount)-self.minimumLineSpacing)
}
}
// 将设置好存放每个item的布局信息返回
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attributeArray
}
}
ViewController 类
import UIKit
class ViewController: UIViewController, UICollisionBehaviorDelegate, UICollectionViewDataSource, UICollectionViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let layout = WaterFallLayout(itemCount: 30)
let collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(NSClassFromString("UICollectionViewCell"), forCellWithReuseIdentifier: "itemID")
self.view.addSubview(collectionView)
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "itemID", for: indexPath)
cell.backgroundColor = UIColor(red: CGFloat(arc4random()%255)/255, green: CGFloat(arc4random()%255)/255, blue: CGFloat(arc4random()%255)/255, alpha: 1)
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("点击了第\(indexPath.row)个item")
}
}
网友评论