swift瀑布流自定义布局实现
2016-04-29 11:58
465 查看
demo github下载地址
https://github.com/liwei5bao/SwiftWaterfallProject
// ViewController.swift
// SwiftWaterfall
import UIKit
import UIKit
class ViewController:UIViewController{
var collectionView:UICollectionView?
///重用item的标识
let itwmID =
"shopID"
///商品数组
lazy
var shops:NSMutableArray? = {
returnNSMutableArray()
}()
override
func viewDidLoad() {
super.viewDidLoad()
//初始化布局
self.setupLayout()
//初始化上拉加载更多,下拉加载
self.setupRefresh()
self.loadNewShops()
}
//MARK:初始化数据
private
func setupList(){
for i
in 0...10{
var model:NSDictionary?
if
Int(i % 2) ==
0{
model = ["w":NSNumber(int:200),"h":NSNumber(int:300),"img":"http://s6.mogujie.cn/b7/bao/131008/q2o17_kqyvcz3ckfbewv3wgfjeg5sckzsew_330x445.jpg_200x999.jpg","price":""]
}else{
model = ["w":NSNumber(int:200),"h":NSNumber(int:400),"img":"http://s6.mogujie.cn/b7/bao/131008/q2o17_kqyvcz3ckfbewv3wgfjeg5sckzsew_330x445.jpg_200x999.jpg","price":""]
}
self.shops?.addObject(model!)
}
self.collectionView?.header.endRefreshing()
self.collectionView?.footer.endRefreshing()
}
//MARK:初始化的内容
private
func setupRefresh(){
self.collectionView?.addLegendHeaderWithRefreshingTarget(self,
refreshingAction: "loadNewShops")//header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: "loadNewShops")
self.collectionView?.addLegendFooterWithRefreshingTarget(self,
refreshingAction: "loadMoreShops")//footer = MJRefreshAutoFooter(refreshingTarget: self, refreshingAction: "loadMoreShops")
self.collectionView?.footer.hidden =true
}
private
func setupLayout(){
let layout =
OOWaterflowLayout()
layout.delegate =self
//创建collectionView
let collectionView =
UICollectionView(frame:
self.view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor =UIColor.whiteColor()
collectionView.dataSource =self
self.view.addSubview(collectionView)
collectionView.registerNib(UINib(nibName:"OOShopCell", bundle:
nil), forCellWithReuseIdentifier:
itwmID)
self.collectionView = collectionView
}
///加载新数据
func loadNewShops(){
self.shops?.removeAllObjects()
self.setupList()
//刷新数据
self.collectionView?.reloadData()
self.collectionView?.header.endRefreshing()
}
///加载更多的数据
func loadMoreShops(){
self.setupList()
//刷新数据
self.collectionView?.reloadData()
self.collectionView?.footer.endRefreshing()
}
override
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController:UICollectionViewDataSource{
//MARK:UICollectionViewDataSource的数据源
func collectionView(collectionView:
UICollectionView, numberOfItemsInSection section:
Int) -> Int {
self.collectionView?.footer.hidden = (self.shops?.count
== 0)
return (self.shops?.count)!
}
func collectionView(collectionView:
UICollectionView, cellForItemAtIndexPath indexPath:
NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(itwmID,
forIndexPath: indexPath)as?
OOShopCell
cell?.shops =self.shops![indexPath.item]as?
NSDictionary
return cell!
}
}
extension ViewController:OOWaterflowLayoutDeledate{
///必须实现的方法
func waterflowLayout(waterflowLayout waterflowLayout:OOWaterflowLayout, heightForItemAtIndex index:NSInteger,
itemWidth width: CGFloat) ->
CGFloat {
let shop =
self.shops![index]as!
NSDictionary
return width *
CGFloat(shop["h"]as!
NSNumber) /CGFloat(shop["w"] as!
NSNumber)
}
//MARK:下边的代理可以不实现有默认值
///返回列数
func columnCountInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
NSInteger {
return
2
}
///返回列间距
func columnMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
CGFloat {
return
10
}
///返回行间距
func rowMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
CGFloat {
return
10
}
///返回内边距
func edgeInsetsInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
UIEdgeInsets {
return
UIEdgeInsetsMake(20,10,
10, 10)
}
}
// OOWaterflowLayout.swift
// swift瀑布流
import UIKit
class OOWaterflowLayout:UICollectionViewLayout {
///代理
weakvar delegate:OOWaterflowLayoutDeledate?
///默认的列数
let OODefaultColumnCount:NSInteger =2
/**
每一列之间的间距 */
let OODefaultColumnMargin:CGFloat =10
/**
每一行之间的间距 */
let OODefaultRowMargin:CGFloat =10
/**
边缘间距 */
let OODefaultEdgeInsets:UIEdgeInsets =UIEdgeInsetsMake(10,10,
10, 10)
/**
存放所有cell的布局属性 */
lazyvar attrsArray:[UICollectionViewLayoutAttributes]
= {return [UICollectionViewLayoutAttributes]()}()
/**
存放所有列的当前高度 */
lazy
var columnHeights:NSMutableArray = {returnNSMutableArray()}()
var contentHeight:CGFloat?
///行间距
var rowMargin:CGFloat{
get{
if ((self.delegate?.respondsToSelector("rowMarginInWaterflowLayout:"))
== true){
return (self.delegate?.rowMarginInWaterflowLayout!(self))!
}else{
returnOODefaultRowMargin
}
}
}
///列间距
var columnMargin:CGFloat{
get{
if ((self.delegate?.respondsToSelector("columnMarginInWaterflowLayout:"))
== true){
return (self.delegate?.columnMarginInWaterflowLayout!(self))!
}else{
returnOODefaultColumnMargin
}
}
}
///列数
var columnCount:NSInteger{
get{
if ((self.delegate?.respondsToSelector("columnMarginInWaterflowLayout:"))
== true){
return (self.delegate?.columnCountInWaterflowLayout!(self))!
}else{
returnOODefaultColumnCount
}
}
}
///边距
var edgeInsets:UIEdgeInsets{
get{
if ((self.delegate?.respondsToSelector("edgeInsetsInWaterflowLayout:"))
== true){
return (self.delegate?.edgeInsetsInWaterflowLayout!(self))!
}else{
returnOODefaultEdgeInsets
}
}
}
}
//MARK:初始化和计算
extension OOWaterflowLayout{
///1.布局的初始化操作
override
func prepareLayout() {
super.prepareLayout()
self.contentHeight =0
//清除之前计算的高度
self.columnHeights.removeAllObjects()
for
_ in
0...self.columnCount -1{
self.columnHeights.addObject(self.edgeInsets.top)
}
//清除之前所有的布局属性
self.attrsArray.removeAll()
//创建每一个cell的布局属性
let count =self.collectionView?.numberOfItemsInSection(0)
for
var i =0;i < count;i++ {
let indexpath =
NSIndexPath(forItem: i, inSection:0)
//获取布局属性
let attrs =self.layoutAttributesForItemAtIndexPath(indexpath)
self.attrsArray.append(attrs!)
}
}
///2.决定cell的排布
override
func layoutAttributesForElementsInRect(rect:CGRect) -> [UICollectionViewLayoutAttributes]? {
return
self.attrsArray
}
///3.返回indexPath位置cell对应的布局属性
override
func layoutAttributesForItemAtIndexPath(indexPath:NSIndexPath) ->
UICollectionViewLayoutAttributes? {
//创建布局属性
let attrs =
UICollectionViewLayoutAttributes(forCellWithIndexPath:indexPath)
//创建collectionView的宽度
let collectionViewW =
self.collectionView?.frame.size.width
let coCount:CGFloat =CGFloat(NSNumber(integer:self.columnCount))
//设置布局的frame
let w:CGFloat = (collectionViewW! -self.edgeInsets.left
-self.edgeInsets.right - (coCount -1) *
self.columnMargin) / coCount
let h:CGFloat = (self.delegate?.waterflowLayout(waterflowLayout:self,
heightForItemAtIndex: indexPath.item, itemWidth: w))!
//找出高度最短的那一列
var destColumn:CGFloat =0
var minColumnHeight:CGFloat = (self.columnHeights[0]as?
CGFloat)!
for
var i =1;i <
self.columnCount;i++ {
let columnHeight = (self.columnHeights[i]as?
CGFloat)!
if minColumnHeight > columnHeight{
minColumnHeight = columnHeight
destColumn =CGFloat(i)
}
}
let x:CGFloat =self.edgeInsets.left
+ destColumn * (w +self.columnMargin)
var y:CGFloat = minColumnHeight
if y !=
self.edgeInsets.top{
y +=self.rowMargin
}
attrs.frame =CGRectMake(x, y, w, h)
//更新最短的那一列的高度
self.columnHeights[NSInteger(destColumn)] =CGRectGetMaxY(attrs.frame)
//记录内容的高度
let columnHeight:CGFloat =self.columnHeights[NSInteger(destColumn)]as!
CGFloat
if
self.contentHeight < columnHeight{
self.contentHeight = columnHeight
}
return attrs
}
override
func collectionViewContentSize() ->CGSize {
returnCGSizeMake(0,self.contentHeight!
+self.edgeInsets.bottom)
}
}
//MARK:代理
@objcprotocol OOWaterflowLayoutDeledate:NSObjectProtocol{
///返回每个item的高度必须实现
func waterflowLayout(waterflowLayout waterflowLayout:OOWaterflowLayout,heightForItemAtIndex index:NSInteger,itemWidth
width:CGFloat)->CGFloat
///返回的列数不实现默认为3列
optional
func columnCountInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->NSInteger
///返回列间距,默认为10
optional
func columnMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->CGFloat
///返回行间距,默认为10
optional
func rowMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->CGFloat
///返回内边距,默认为(10,10,10,10)
optional
func edgeInsetsInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->UIEdgeInsets
}
https://github.com/liwei5bao/SwiftWaterfallProject
// ViewController.swift
// SwiftWaterfall
import UIKit
import UIKit
class ViewController:UIViewController{
var collectionView:UICollectionView?
///重用item的标识
let itwmID =
"shopID"
///商品数组
lazy
var shops:NSMutableArray? = {
returnNSMutableArray()
}()
override
func viewDidLoad() {
super.viewDidLoad()
//初始化布局
self.setupLayout()
//初始化上拉加载更多,下拉加载
self.setupRefresh()
self.loadNewShops()
}
//MARK:初始化数据
private
func setupList(){
for i
in 0...10{
var model:NSDictionary?
if
Int(i % 2) ==
0{
model = ["w":NSNumber(int:200),"h":NSNumber(int:300),"img":"http://s6.mogujie.cn/b7/bao/131008/q2o17_kqyvcz3ckfbewv3wgfjeg5sckzsew_330x445.jpg_200x999.jpg","price":""]
}else{
model = ["w":NSNumber(int:200),"h":NSNumber(int:400),"img":"http://s6.mogujie.cn/b7/bao/131008/q2o17_kqyvcz3ckfbewv3wgfjeg5sckzsew_330x445.jpg_200x999.jpg","price":""]
}
self.shops?.addObject(model!)
}
self.collectionView?.header.endRefreshing()
self.collectionView?.footer.endRefreshing()
}
//MARK:初始化的内容
private
func setupRefresh(){
self.collectionView?.addLegendHeaderWithRefreshingTarget(self,
refreshingAction: "loadNewShops")//header = MJRefreshNormalHeader(refreshingTarget: self, refreshingAction: "loadNewShops")
self.collectionView?.addLegendFooterWithRefreshingTarget(self,
refreshingAction: "loadMoreShops")//footer = MJRefreshAutoFooter(refreshingTarget: self, refreshingAction: "loadMoreShops")
self.collectionView?.footer.hidden =true
}
private
func setupLayout(){
let layout =
OOWaterflowLayout()
layout.delegate =self
//创建collectionView
let collectionView =
UICollectionView(frame:
self.view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor =UIColor.whiteColor()
collectionView.dataSource =self
self.view.addSubview(collectionView)
collectionView.registerNib(UINib(nibName:"OOShopCell", bundle:
nil), forCellWithReuseIdentifier:
itwmID)
self.collectionView = collectionView
}
///加载新数据
func loadNewShops(){
self.shops?.removeAllObjects()
self.setupList()
//刷新数据
self.collectionView?.reloadData()
self.collectionView?.header.endRefreshing()
}
///加载更多的数据
func loadMoreShops(){
self.setupList()
//刷新数据
self.collectionView?.reloadData()
self.collectionView?.footer.endRefreshing()
}
override
func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController:UICollectionViewDataSource{
//MARK:UICollectionViewDataSource的数据源
func collectionView(collectionView:
UICollectionView, numberOfItemsInSection section:
Int) -> Int {
self.collectionView?.footer.hidden = (self.shops?.count
== 0)
return (self.shops?.count)!
}
func collectionView(collectionView:
UICollectionView, cellForItemAtIndexPath indexPath:
NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(itwmID,
forIndexPath: indexPath)as?
OOShopCell
cell?.shops =self.shops![indexPath.item]as?
NSDictionary
return cell!
}
}
extension ViewController:OOWaterflowLayoutDeledate{
///必须实现的方法
func waterflowLayout(waterflowLayout waterflowLayout:OOWaterflowLayout, heightForItemAtIndex index:NSInteger,
itemWidth width: CGFloat) ->
CGFloat {
let shop =
self.shops![index]as!
NSDictionary
return width *
CGFloat(shop["h"]as!
NSNumber) /CGFloat(shop["w"] as!
NSNumber)
}
//MARK:下边的代理可以不实现有默认值
///返回列数
func columnCountInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
NSInteger {
return
2
}
///返回列间距
func columnMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
CGFloat {
return
10
}
///返回行间距
func rowMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
CGFloat {
return
10
}
///返回内边距
func edgeInsetsInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->
UIEdgeInsets {
return
UIEdgeInsetsMake(20,10,
10, 10)
}
}
// OOWaterflowLayout.swift
// swift瀑布流
import UIKit
class OOWaterflowLayout:UICollectionViewLayout {
///代理
weakvar delegate:OOWaterflowLayoutDeledate?
///默认的列数
let OODefaultColumnCount:NSInteger =2
/**
每一列之间的间距 */
let OODefaultColumnMargin:CGFloat =10
/**
每一行之间的间距 */
let OODefaultRowMargin:CGFloat =10
/**
边缘间距 */
let OODefaultEdgeInsets:UIEdgeInsets =UIEdgeInsetsMake(10,10,
10, 10)
/**
存放所有cell的布局属性 */
lazyvar attrsArray:[UICollectionViewLayoutAttributes]
= {return [UICollectionViewLayoutAttributes]()}()
/**
存放所有列的当前高度 */
lazy
var columnHeights:NSMutableArray = {returnNSMutableArray()}()
var contentHeight:CGFloat?
///行间距
var rowMargin:CGFloat{
get{
if ((self.delegate?.respondsToSelector("rowMarginInWaterflowLayout:"))
== true){
return (self.delegate?.rowMarginInWaterflowLayout!(self))!
}else{
returnOODefaultRowMargin
}
}
}
///列间距
var columnMargin:CGFloat{
get{
if ((self.delegate?.respondsToSelector("columnMarginInWaterflowLayout:"))
== true){
return (self.delegate?.columnMarginInWaterflowLayout!(self))!
}else{
returnOODefaultColumnMargin
}
}
}
///列数
var columnCount:NSInteger{
get{
if ((self.delegate?.respondsToSelector("columnMarginInWaterflowLayout:"))
== true){
return (self.delegate?.columnCountInWaterflowLayout!(self))!
}else{
returnOODefaultColumnCount
}
}
}
///边距
var edgeInsets:UIEdgeInsets{
get{
if ((self.delegate?.respondsToSelector("edgeInsetsInWaterflowLayout:"))
== true){
return (self.delegate?.edgeInsetsInWaterflowLayout!(self))!
}else{
returnOODefaultEdgeInsets
}
}
}
}
//MARK:初始化和计算
extension OOWaterflowLayout{
///1.布局的初始化操作
override
func prepareLayout() {
super.prepareLayout()
self.contentHeight =0
//清除之前计算的高度
self.columnHeights.removeAllObjects()
for
_ in
0...self.columnCount -1{
self.columnHeights.addObject(self.edgeInsets.top)
}
//清除之前所有的布局属性
self.attrsArray.removeAll()
//创建每一个cell的布局属性
let count =self.collectionView?.numberOfItemsInSection(0)
for
var i =0;i < count;i++ {
let indexpath =
NSIndexPath(forItem: i, inSection:0)
//获取布局属性
let attrs =self.layoutAttributesForItemAtIndexPath(indexpath)
self.attrsArray.append(attrs!)
}
}
///2.决定cell的排布
override
func layoutAttributesForElementsInRect(rect:CGRect) -> [UICollectionViewLayoutAttributes]? {
return
self.attrsArray
}
///3.返回indexPath位置cell对应的布局属性
override
func layoutAttributesForItemAtIndexPath(indexPath:NSIndexPath) ->
UICollectionViewLayoutAttributes? {
//创建布局属性
let attrs =
UICollectionViewLayoutAttributes(forCellWithIndexPath:indexPath)
//创建collectionView的宽度
let collectionViewW =
self.collectionView?.frame.size.width
let coCount:CGFloat =CGFloat(NSNumber(integer:self.columnCount))
//设置布局的frame
let w:CGFloat = (collectionViewW! -self.edgeInsets.left
-self.edgeInsets.right - (coCount -1) *
self.columnMargin) / coCount
let h:CGFloat = (self.delegate?.waterflowLayout(waterflowLayout:self,
heightForItemAtIndex: indexPath.item, itemWidth: w))!
//找出高度最短的那一列
var destColumn:CGFloat =0
var minColumnHeight:CGFloat = (self.columnHeights[0]as?
CGFloat)!
for
var i =1;i <
self.columnCount;i++ {
let columnHeight = (self.columnHeights[i]as?
CGFloat)!
if minColumnHeight > columnHeight{
minColumnHeight = columnHeight
destColumn =CGFloat(i)
}
}
let x:CGFloat =self.edgeInsets.left
+ destColumn * (w +self.columnMargin)
var y:CGFloat = minColumnHeight
if y !=
self.edgeInsets.top{
y +=self.rowMargin
}
attrs.frame =CGRectMake(x, y, w, h)
//更新最短的那一列的高度
self.columnHeights[NSInteger(destColumn)] =CGRectGetMaxY(attrs.frame)
//记录内容的高度
let columnHeight:CGFloat =self.columnHeights[NSInteger(destColumn)]as!
CGFloat
if
self.contentHeight < columnHeight{
self.contentHeight = columnHeight
}
return attrs
}
override
func collectionViewContentSize() ->CGSize {
returnCGSizeMake(0,self.contentHeight!
+self.edgeInsets.bottom)
}
}
//MARK:代理
@objcprotocol OOWaterflowLayoutDeledate:NSObjectProtocol{
///返回每个item的高度必须实现
func waterflowLayout(waterflowLayout waterflowLayout:OOWaterflowLayout,heightForItemAtIndex index:NSInteger,itemWidth
width:CGFloat)->CGFloat
///返回的列数不实现默认为3列
optional
func columnCountInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->NSInteger
///返回列间距,默认为10
optional
func columnMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->CGFloat
///返回行间距,默认为10
optional
func rowMarginInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->CGFloat
///返回内边距,默认为(10,10,10,10)
optional
func edgeInsetsInWaterflowLayout(waterflowLayout:OOWaterflowLayout) ->UIEdgeInsets
}
相关文章推荐
- Apple Swift学习教程
- 介绍 Fedora 上的 Swift
- 异步加载技术实现当滚动条到最底部的瀑布流效果
- 基于JavaScript实现瀑布流布局
- 基于JavaScript实现瀑布流效果(循环渐近)
- 原生JS实现美图瀑布流布局赏析
- 详解javascript实现瀑布流列式布局
- javascript瀑布流式图片懒加载实例
- javascript实现仿百度图片的瀑布流加载效果
- avalonjs制作响应式瀑布流特效
- javascript实现瀑布流加载图片原理
- jquery 插件实现瀑布流图片展示实例
- jquery代码实现简单的随机图片瀑布流效果
- 深入探秘jquery瀑布流的实现
- JavaScript实现图片自动加载的瀑布流效果
- jQuery.lazyload+masonry改良图片瀑布流代码
- Swift中实现点击、双击、捏、旋转、拖动、划动、长按手势的类和方法介绍
- Swift自定义iOS中的TabBarController并为其添加动画
- Swift编程中的泛型解析