//
// ViewController.swift
// TGWaterfall
//
// Created by targetcloud on 2017/3/23.
// Copyright © 2017年 targetcloud. All rights reserved.
//
import UIKit
private let kCollectionVCellID = "kCollectionVCellID"
class ViewController: UIViewController {
var itemCount = 30
fileprivate lazy var collectionView : UICollectionView = {
let layout = TGWaterfallLayout()
layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 10
layout.cols = 2
layout.dataSource = self
let collectionV = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
collectionV.dataSource = self
collectionV.delegate = self
collectionV.register(UICollectionViewCell.self, forCellWithReuseIdentifier: kCollectionVCellID)
return collectionV
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
// Do any additional setup after loading the view, typically from a nib.
}
}
extension ViewController:UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return itemCount
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: kCollectionVCellID, for: indexPath)
cell.backgroundColor = UIColor.random()
var label :UILabel? = cell.contentView.subviews.first as? UILabel
if label == nil{
label = UILabel(frame: cell.bounds)
label?.textAlignment = .center
cell.contentView.addSubview(label!)
}
label?.text = "\(indexPath.item)"
/*
如果代码打开的话,最后的 return cell 则不会执行到,导致循环利用CELL的BUG
if itemCount - 1 == indexPath.item {
itemCount += 30
collectionView.reloadData()
}
*/
return cell
}
}
extension ViewController:UICollectionViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {//上拉加载更多效果
itemCount += 30
collectionView.reloadData()
}
}
}
extension ViewController:TGWaterfallLayoutDataSource{
func waterfallLayout(_ layout: TGWaterfallLayout, itemIndex: Int) -> CGFloat {
//return CGFloat(arc4random_uniform(150) + 50)
let screenW = UIScreen.main.bounds.width
return itemIndex % 2 == 0 ? screenW * 2 / 3 : screenW * 0.5
}
}
TGWaterfallLayout的实现
//
// TGWaterfallLayout.swift
// TGWaterfall
//
// Created by targetcloud on 2017/3/23.
// Copyright © 2017年 targetcloud. All rights reserved.
//
import UIKit
protocol TGWaterfallLayoutDataSource:class {
func waterfallLayout(_ layout :TGWaterfallLayout,itemIndex : Int) -> CGFloat
}
class TGWaterfallLayout: UICollectionViewFlowLayout {
weak var dataSource : TGWaterfallLayoutDataSource?
var cols = 4
fileprivate lazy var attributes :[UICollectionViewLayoutAttributes] = [UICollectionViewLayoutAttributes]()
fileprivate lazy var maxH : CGFloat = self.sectionInset.top + self.sectionInset.bottom
fileprivate lazy var heights : [CGFloat] = Array(repeating: self.sectionInset.top, count: self.cols)
override func prepare() {
super.prepare()
//attributes.removeAll()
guard let collectionView = collectionView else {
return
}
let count = collectionView.numberOfItems(inSection: 0)
let itemW = (collectionView.bounds.width - sectionInset.left - sectionInset.right - CGFloat(cols-1) * minimumInteritemSpacing) / CGFloat(cols)
for i in attributes.count..<count{
/*
//let itemH = CGFloat(arc4random_uniform(150) + 50)
*/
//正式使用时请使用这里
guard let itemH = dataSource?.waterfallLayout(self, itemIndex: i) else{
fatalError("请检查数据源")
}
/*
let itemH = dataSource?.waterfallLayout(self, itemIndex: i) ?? CGFloat(arc4random_uniform(150) + 50)//test
*/
let minH = heights.min()!
let minIndex = heights.index(of: minH)!
let itemX = sectionInset.left + (minimumInteritemSpacing + itemW) * CGFloat(minIndex)
let indexPath = IndexPath(item: i, section: 0)
let itemY = minH
//heights[minIndex] = itemY
let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attribute.frame = CGRect(x: itemX, y: itemY, width: itemW, height: itemH)
attributes.append(attribute)
heights[minIndex] = attribute.frame.maxY + minimumLineSpacing
}
maxH = heights.max()! - minimumLineSpacing
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return attributes
}
override var collectionViewContentSize: CGSize{
return CGSize(width: 0, height: maxH + sectionInset.bottom)
}
}