1.viewcontroller 設定collectionView布局資訊
import UIKit
import SDWebImage
import MJRefresh
class YFWaterFallViewController:UIViewController,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout,YFWaterFallLayoutDelegate {
let cellID ="waterID"
var dataLists =Array<YFVideoInfo>()
var collectionView :UICollectionView!
let header =MJRefreshNormalHeader()//頂部重新整理
let footer =MJRefreshAutoNormalFooter()//底部重新整理
overridefunc viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor =UIColor.whiteColor()
self.navigationItem.title ="瀑布流"
let layout :YFWaterFallCollectionLayout =YFWaterFallCollectionLayout()
layout.delegate =self
self.collectionView =UICollectionView(frame:CGRectMake(0,0,screenWidth,screenHeight), collectionViewLayout: layout)
collectionView.dataSource =self
collectionView.backgroundColor =UIColor.lightGrayColor()
collectionView.registerClass(YFWaterFallCollectionViewCell.self, forCellWithReuseIdentifier: cellID)
header.setRefreshingTarget(self, refreshingAction:#selector(YFWaterFallViewController.headerRefresh))
collectionView.mj_header =header
footer.setRefreshingTarget(self, refreshingAction:#selector(YFWaterFallViewController.footerRefresh))
collectionView.mj_footer =footer
self.view.addSubview(collectionView)
self.loadData()
}
func headerRefresh() {
self.dataLists = [YFVideoInfo]()
self.loadData()
}
func footerRefresh() {
self.loadData()
}
//資料載入過程
func loadData() {
var params:Dictionary<String,String> = [:]
params["sign"] =swSign
YFHttpTool.POST("http://......", parameters: params, success: { (operation, responseObject) in
YFAlertView.hideHud(self.view)
if responseObject?.objectForKey("status")as!NSNumber ==1 {
let tmpArray :NSArray = responseObject!.objectForKey("info")as!NSArray
for dictin tmpArray {
let model :YFVideoInfo =YFVideoInfo.ljbObjectWithDict(dictas!Dictionary)
let sizeDict = dict.objectForKey("imgSize")
model.w = sizeDict!.objectForKey("width")as?NSNumber
model.h = sizeDict!.objectForKey("height")as?NSNumber
self.dataLists.append(model)
}
self.collectionView.reloadData()
self.collectionView.mj_header.endRefreshing()
self.collectionView.mj_footer.endRefreshing()
} else {
YFAlertView.showErrorText("查詢失敗!", view: self.view)
}
}) { (operation, error) in
print("error:\(error)")
YFAlertView.hideHud(self.view)
YFAlertView.showErrorText("網路連接異常!", view: self.view)
}
}
//collectionView資料來源設定
func collectionView(collectionView:UICollectionView, numberOfItemsInSection section:Int) -> Int {
returnself.dataLists.count
}
//給layout高度,根據比例計算
func collectionView(collectionView:UICollectionView, cellForItemAtIndexPath indexPath:NSIndexPath) -> UICollectionViewCell {
let cell :YFWaterFallCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier(self.cellID, forIndexPath: indexPath) as!YFWaterFallCollectionViewCell
cell.model =self.dataLists[indexPath.row]
return cell
}
//layout代理
func waterFallLayout(layout:UICollectionViewFlowLayout, index:NSInteger, width: CGFloat) -> CGFloat {
let model :YFVideoInfo =self.dataLists[index]
return width / (CGFloat((model.w?.floatValue)!) / CGFloat((model.h?.floatValue)!))
}
func columnCountOfWaterFallLayout(layout:UICollectionViewFlowLayout) ->NSInteger {
return2
}
overridefunc didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
2.cell設定,重新layoutSubviews,防止錯位
import UIKit
class YFWaterFallCollectionViewCell:UICollectionViewCell {
//資料被賦值時初始化item資料
var model :YFVideoInfo? {
didSet {
let url =NSURL(string:"http://xxx.xxx.cn\(model!.videoImgUrl)")
self.imageView.sd_setImageWithURL(url)
}
}
let imageView :UIImageView =UIImageView()
overrideinit(frame:CGRect) {
super.init(frame: frame)
self.imageView.frame =CGRectMake(0,0, frame.size.width, frame.size.height)
self.addSubview(self.imageView)
}
requiredinit?(coder aDecoder:NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//重新布局,否則二次重新整理時由於儲存格重用導致錯位
overridefunc layoutSubviews() {
super.layoutSubviews()
self.imageView.frame =CGRectMake(0,0,self.frame.size.width,self.frame.size.height)
}
}
3.自訂UICollectionViewFlowLayout類
import UIKit
protocol YFWaterFallLayoutDelegate {
// 返回index位置下的item的高度
func waterFallLayout(layout:UICollectionViewFlowLayout,index :NSInteger,width :CGFloat) ->CGFloat
// 返回瀑布流顯示的列數
func columnCountOfWaterFallLayout(layout:UICollectionViewFlowLayout) ->NSInteger
}
class YFWaterFallCollectionLayout:UICollectionViewFlowLayout {
var delegate :YFWaterFallLayoutDelegate?
var attributesArray = [UICollectionViewLayoutAttributes]()//布局資訊儲存,防止下拉看到二次地區時,多次返回布局資訊。
var columnHeights =Array<Float>()//儲存當前行的列的高度資訊。
var columnCount :Int =2//預設列數
var edgeInsets :UIEdgeInsets =UIEdgeInsets(top:5, left: 5, bottom:5, right:5)
var columnMargin :CGFloat =5//列距
var rowMargin :CGFloat =5//行距
overridefunc prepareLayout() {
super.prepareLayout()
//初始化最大高度資料集合
columnHeights =Array<Float>()
self.columnCount = (self.delegate?.columnCountOfWaterFallLayout(self))!
ifself.columnCount <=0 {
return;
}
for_in0..<columnCount {
columnHeights.append(Float(self.edgeInsets.top))
}
//初始化布局資訊資料來源
attributesArray = [UICollectionViewLayoutAttributes]()
let cellCount =self.collectionView!.numberOfItemsInSection(0)
for iin0..<cellCount {
let indexPath = NSIndexPath(forItem:i, inSection:0)
let attributes =self.layoutAttributesForItemAtIndexPath(indexPath)
attributesArray.append(attributes!)
}
}
// 所有儲存格位置屬性
overridefunc layoutAttributesForElementsInRect(rect:CGRect)
-> [UICollectionViewLayoutAttributes]? {
returnself.attributesArray
}
// 這個方法返回每個儲存格的位置和大小
overridefunc layoutAttributesForItemAtIndexPath(indexPath:NSIndexPath) -> UICollectionViewLayoutAttributes? {
let attribute =UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
let collectionViewWidth :CGFloat =self.collectionView!.frame.size.width
let width :CGFloat = (collectionViewWidth -self.edgeInsets.left -self.edgeInsets.right - (CGFloat(self.columnCount) - 1) * self.columnMargin) /CGFloat(self.columnCount);
// 計算當前item應該擺放在第幾列(計算哪一列高度最短)
var minColumn :Int =0//預設是第0列
var minHeight :Float =MAXFLOAT
// 遍曆找出最小高度的列,在最小列的下面新增。
for (index,value)inself.columnHeights.enumerate() {
if minHeight > value {
minHeight = value
minColumn = index
}
}
let x :CGFloat =self.edgeInsets.left +CGFloat(minColumn) * (width +self.columnMargin)
let y :CGFloat =CGFloat(minHeight) +self.rowMargin
let height :CGFloat = (self.delegate?.waterFallLayout(self, index: indexPath.row, width: width))!
attribute.frame =CGRectMake(x, y, width, height)
// // 更新數組中的最短列的高度
self.columnHeights[minColumn] =Float(y + height)
return attribute
}
&nbs