您的位置:首页 > 移动开发 > Swift

swift简单瀑布流的实现

2016-06-17 14:40 465 查看


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

    }

    

   
// 内容区域总大小,不是可见区域

    overridefunc collectionViewContentSize() ->CGSize {

       
//每次加载时,重新计算最大高度。防止多次下拉时看不到更多区域。

        var maxHeight :Float =0

        for (_,value)inself.columnHeights.enumerate()
{

            if value > maxHeight {

                maxHeight = value

            }

        }

        returnCGSizeMake(0,CGFloat(maxHeight)
+ self.edgeInsets.top)

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: