>

用collectionView做瀑布流,布局贰个collectionView瀑布

- 编辑:澳门新葡亰平台游戏 -

用collectionView做瀑布流,布局贰个collectionView瀑布

- prepareLayout { [super prepareLayout]; /** 清空属性数组. */ if (self.attributesArray != nil) { [self.attributesArray removeAllObjects]; } /** 根据列数进行遍历, 给骑士的每列都加上边界的距离. */ /** 数据列数进行遍历. */ for (NSInteger i = 0; i < self.columnCounts; i++) { NSString *key = [NSString stringWithFormat:@"%ld", i]; self.columnDic[key] = @(self.edgeInsets.top); } /** 遍历每个item. */ NSInteger count = [self.collectionView numberOfItemsInSection:0]; for (int i = 0; i < count; i++) { [self setItemFrame:i]; }}

}-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionViews cellForItemAtIndexPath:(NSIndexPath*)indexPath{CollectionCell*cell = (CollectionCell *)[collectionViewsdequeueReusableCellWithReuseIdentifier:@"CollectionCell"forIndexPath:indexPath];cell.backgroundColor=[UIColor clearColor];//图片名称//NSString *imageToLoad = [NSString stringWithFormat:@"%d.png", indexPath.row];NSDictionary*item=productList[indexPath.row];NSString*productName;NSString*productImgUrl;if([dataTypeps isEqualToString:TYPE_HISTORY]){NSArray*temp=[[item objectForKey:PRODUCT_NAME] componentsSeparatedByString:@":"];productName=temp[0];}else{productName=[item objectForKey:PRODUCT_NAME];}UIImage*img=[item objectForKey:KEY_PRODUCT_IMG];CGSize size=[selfgetImgSize:img];//加载图片cell.imageView.image=img;cell.imageView.frame=CGRectMake(0,0, size.width, size.height);//--------------//透明栏//--------------floath=30;floatx=0;floatw=size.width;floaty=size.height-h;cell.bottomBar.frame=CGRectMake(x, y, w, h);cell.bottomBar.backgroundColor=[UIColor clearColor];//产品名y=0;floattempH=h/2;x=3;cell.productNameLbl.frame=CGRectMake(x, y, w, tempH);cell.productNameLbl.backgroundColor=[UIColor clearColor];[commonUtil setScrollLabel:cell.productNameLbl withText:productName withCenter:UITextAlignmentLeftwithFontSize:14withTextColor:[UIColor whiteColor]];//产品价格y+=tempH;cell.priceLbl.frame=CGRectMake(x, y, w, tempH);cell.priceLbl.text=[NSString stringWithFormat:@"¥%@",[item objectForKey:PRODUCT_PRICE]];returncell;

最后就是我们的ViewController的实现了:
import UIKit

class ViewController: UIViewController {

var width: CGFloat!
var images: Array<UIImage>!
var collectionView:UICollectionView!
var maskView: UIView!
var cellRect: CGRect!
var changeRect: CGRect!
//MARK: --life cycle
override func viewDidLoad() {
    super.viewDidLoad()
    waterfallCollectionView()
}
private func waterfallCollectionView() {
    width = (view.bounds.size.width - 20)/3
    let layout = WaterCollectionViewLayout()
    images = []
    for i in 1..<16 {
        let image = UIImage(named: String.init(format: "%.2d.png", i))
        images.append(image!)
    }
    layout.setSize = {_ in
        return self.images
    }
    collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: layout)
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "newCell")
    collectionView.backgroundColor = UIColor.white
    collectionView.alwaysBounceVertical = true

    collectionView.delegate = self
    collectionView.dataSource = self
    view.addSubview(collectionView)

}

func showPic(btn:UIButton){
    UIView.animate(withDuration: 1, animations: {
        btn.frame = self.cellRect
    }) { (finish) in
        btn.removeFromSuperview()
        self.maskView.removeFromSuperview()
        self.maskView = nil
        self.cellRect = nil
    }
}
}

extension ViewController: UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout {
//MARK: --UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return images.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "newCell", for: indexPath as IndexPath)
    let imageView = UIImageView(frame: cell.bounds)
    imageView.image = images[indexPath.row]
    let bgView = UIView(frame:cell.bounds)
    bgView.addSubview(imageView)
    cell.backgroundView = bgView

    return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)
    maskView = UIView.init(frame: view.bounds)
    maskView.backgroundColor = UIColor.black
    maskView.alpha = 0.5
    view.addSubview(maskView)

    //cell在veiw的位置
    cellRect = cell!.convert(cell!.bounds, to: view)
    let btn = WaterButton.init(frame: cellRect)
    let img = images[indexPath.row]
    btn.wImage = img
    btn.addTarget(self, action: #selector(showPic(btn:)), for: UIControlEvents.touchUpInside)
    view.addSubview(btn)
    //图片长宽的比例与屏幕长宽的比例的对比
    var changeH:CGFloat
    var changeW:CGFloat
    if img.size.width/img.size.height >= view.frame.size.width/view.frame.size.height{
        //对比图片实际宽与屏幕宽
        if img.size.width>view.frame.size.width {
            changeH = img.size.height*view.frame.size.width/img.size.width
            changeRect = CGRect(x: 0, y: (view.frame.size.height-changeH)/2, width:view.frame.size.width, height: changeH)
        }else{
            changeRect = CGRect(x: (view.frame.size.width-img.size.width)/2, y: (view.frame.size.height-img.size.height)/2, width: img.size.width,height: img.size.height)
        }
    }else{
        if img.size.height>view.frame.size.height {
            changeW = img.size.width*view.frame.size.height/img.size.height
            changeRect = CGRect(x: (view.frame.size.width-changeW)/2, y: 0, width: changeW, height: view.frame.size.height)
        }else{
            changeRect = CGRect(x: (view.frame.size.width-img.size.width)/2, y: (view.frame.size.height-img.size.height)/2, width: img.size.width,height: img.size.height)
        }
    }

    UIView.animate(withDuration: 1, animations: {
        btn.frame = self.changeRect
    })

}
}

当然,瀑布流也可以通过tableView来实现,具体的设计思路就不在这里详细说明了,大家可以参考:http://www.jianshu.com/p/78830bdb04a9iOS瀑布流基本实现 很棒的一篇文章哦。

@property (nonatomic, retain) NSMutableDictionary *columnDic; /** 用来存储每一列的Y值. */@property (nonatomic, retain) NSMutableArray *attributesArray; /** 用来存储layout的属性的数组. */

}- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDeletedItemAtIndexPath:(NSIndexPath*)itemIndexPath{UICollectionViewLayoutAttributes* attributes =[selflayoutAttributesForItemAtIndexPath:itemIndexPath];attributes.alpha=0.0;attributes.center=CGPointMake(_center.x, _center.y);attributes.transform3D= CATransform3DMakeScale(0.1,0.1,1.0);returnattributes;

再来自定义一个button--WaterButton来实现点击cell得到大图
import UIKit

class WaterButton: UIButton {

var wImage:UIImage!{
    didSet{
        wImageView.image = wImage
    }
}
private var wImageView:UIImageView!
override init(frame: CGRect) {
    super.init(frame: frame)
    wImageView = UIImageView(frame:bounds)
    addSubview(wImageView)
}

override func layoutSubviews() {
    super.layoutSubviews()
    wImageView.frame = bounds
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}
}
- setItemFrame:(NSInteger)index { __block NSString *minColumn = @"0"; [self.columnDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { if ([obj floatValue] < [self.columnDic[minColumn] floatValue]) { minColumn = key; } }]; CGFloat width = ((WIDTH - self.edgeInsets.left - self.edgeInsets.right - (self.columnCounts - 1) * self.columnSpace)) / self.columnCounts; /** x坐标 = 左间距 +  * 列的下标. */ /** 列的小标对应的是最短下标. */ CGFloat x = _edgeInsets.left + (width + _columnSpace) * [minColumn floatValue]; /** 创建一个indexPath. */ NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0]; /** 高. */ CGFloat height = [self.delegate layout:self heightFroItenAtIndexPath:indexPath Width:width]; /** 先找到当前最短一列的Y值. */ CGFloat minY = [self.columnDic[minColumn] floatValue]; /** 为最短的一列更新Y周的高度 = minY + 高 + 行间距 */ self.columnDic[minColumn] = @(minY + height + self.rowSpace); /** 这个类用来设置 item 的 frame , bounds 等属性的. */ UICollectionViewLayoutAttributes *layoutAttributed = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; layoutAttributed.frame = CGRectMake(x, minY, width, height); [self.attributesArray addObject:layoutAttributed]; }

ios UICollectionView实现瀑布流 

我们在用collectionView的时候难免会觉得整齐的框框放在那有些单调,大脸猫给大家分享一个小demo,用collectionView实现瀑布流。效果如下:

图片 1

swift-collectionView实现瀑布流.gif

3.可以在.m文件中再写连个属性

}- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForInsertedItemAtIndexPath:(NSIndexPath*)itemIndexPath{UICollectionViewLayoutAttributes* attributes =[selflayoutAttributesForItemAtIndexPath:itemIndexPath];attributes.alpha=0.0;attributes.center=CGPointMake(_center.x, _center.y);returnattributes;

首先,自定义一个流水布局WaterCollectionViewLayout,继承UICollectionViewLayout,代码如下:(更新至swift3.0)
import UIKit

class WaterCollectionViewLayout: UICollectionViewLayout {

//来控制cell的大小
var setSize:()->(Array<UIImage>) = {_ in return []}
var queueNum: Int = 2 //列数,默认为两列
var hs: Array<CGFloat>!
private var totalNum: Int!
private var layoutAttributes: Array<UICollectionViewLayoutAttributes>!
override func prepare() {
    super.prepare()
    hs = []
    for _ in 0..<queueNum {
        hs.append(5)
    }
    totalNum = collectionView?.numberOfItems(inSection: 0)
    layoutAttributes = []
    var indexpath: NSIndexPath!
    for index in 0..<totalNum {
        indexpath = NSIndexPath(row: index, section: 0)
        let attributes = layoutAttributesForItem(at: indexpath as IndexPath)
        layoutAttributes.append(attributes!)
    }
}
private let gap:CGFloat = 5//间隔,缝隙大小
private var width:CGFloat!
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    width = (collectionView!.bounds.size.width-gap*(CGFloat(queueNum)-1))/CGFloat(queueNum)
    let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
    let sizes = setSize()
    attributes.size = CGSize(width: width, height: sizes[indexPath.row].size.height*width/sizes[indexPath.row].size.width)
    var nub:CGFloat = 0
    var h:CGFloat = 0
    (nub,h) = minH(hhs: hs)
    attributes.center = CGPoint(x:(nub+0.5)*(gap+width), y:h+(width/attributes.size.width*attributes.size.height+gap)/2)
    hs[Int(nub)] = h+width/attributes.size.width*attributes.size.height+gap
    return attributes
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    return layoutAttributes
}

//    override func collectionViewContentSize() -> CGSize {
//        return CGSize(width: (collectionView?.bounds.width)!, height: maxH(hhs: hs))
//    }
//swift3.0废弃了上面这个方法,所以我们改成重写collectionViewContentSize属性
override var collectionViewContentSize: CGSize {
    get {
        return CGSize(width: (collectionView?.bounds.width)!, height: maxH(hhs: hs))
    }
    set {
        self.collectionViewContentSize = newValue
    }
}

private func minH(hhs:Array<CGFloat>)->(CGFloat,CGFloat){
    var num = 0
    var min = hhs[0]
    for i in 1..<hhs.count{
        if min>hhs[i] {
            min = hhs[i]
            num = i
        }
    }
    return (CGFloat(num),min)
}
func maxH(hhs:Array<CGFloat>)->CGFloat{
    var max = hhs[0]
    for i in 1..<hhs.count{
        if max<hhs[i] {
            max = hhs[i]
        }
    }
    return max
} 
}

协议方法

@property (strong, nonatomic)  UIImageView*bottomBar;

@class WFCollectionViewLayout;@protocol WFCollectionLayoutDelegate <NSObject>- layout:(WFCollectionViewLayout *)layoutheightFroItenAtIndexPath:(NSIndexPath *)indexPath Width:widthh;@end

如>#import@interfaceCollectionCell : UICollectionViewCell

这个协议方法在创建uicollectionview的界面中实现, 因为在抓取的数据中通常都会有图片的宽度和高度属性. 当我们在collectionView的界面中获取到数据的时候,可以通过这两个属性将每layout的高度返回到自定义的UICOllectionviewFlowLayout类中.通过返回的高度来判断layout的高度.

}- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath  withIndex:(int)index{CGSize itemSize= [self.delegatecollectionView:self.collectionView layout:selfsizeForItemAtIndexPath:indexPath];CGFloat itemHeight= floorf(itemSize.height *self.itemWidth /itemSize.width);UICollectionViewLayoutAttributes*attributes =[UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];index+=1;if(index%2==0){x+=(self.itemWidth+self.sectionInset.left);rightY+=self.sectionInset.top;attributes.frame=CGRectMake(x, rightY,self.itemWidth, itemHeight);rightY+=itemHeight;}else{x=self.sectionInset.left;leftY+=self.sectionInset.top;attributes.frame=CGRectMake(x, leftY,self.itemWidth, itemHeight);leftY+=itemHeight;}returnattributes;

2.为这个类新建一个协议方法

}

5.重写prepareLayout方法, 当collectionView布局layout的时候会调用到这个方法.

}@end三.创建UICollectionView用之前自定义的布局进行初始化并注册之前自定义的UICollectionViewCell,参照如下1.创建变量

6.第四个方法: 把所有的样式返回, 告诉系统如何布局item

@property (strong, nonatomic) CBAutoScrollLabel*productNameLbl;

7.设置滚动范围

@propertyfloatitemWidth;@property (nonatomic, assign) CGPoint center;@property (nonatomic, assign) CGFloat radius;@property (nonatomic, assign) NSInteger cellCount;///The delegate will point to collection view's delegate automatically.@property (nonatomic, weak)iddelegate;///Array to store attributes for all items includes headers, cells, and footers@property (nonatomic, strong) NSMutableArray*allItemAttributes;@property (nonatomic, assign) UIEdgeInsets sectionInset;@end#import"MyLayout.h"#defineITEM_SIZE 70@implementationMyLayout-(void)prepareLayout{[super prepareLayout];self.itemWidth=150;self.sectionInset=UIEdgeInsetsMake(5,5,5,5);self.delegate= (id )self.collectionView.delegate;CGSize size=self.collectionView.frame.size;_cellCount= [[selfcollectionView] numberOfItemsInSection:0];_center= CGPointMake(size.width /2.0, size.height /2.0);_radius= MIN(size.width, size.height) /2.5;

- (instancetype)init { self = [super init]; if  { self.columnDic = [NSMutableDictionary dictionary]; self.attributesArray = [NSMutableArray array]; } return self;}

通过自定义collectionViewCell和重写collectionViewLayout

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:rect { return self.attributesArray;}

}-(CGSize)collectionViewContentSize{returnCGSizeMake(320, (leftY>rightY?leftY:rightY));

  • 首先要做的就是重写UICollectionviewFlowLayout这个类, 自定义一个布局.1.创建一个UICollectionviewFlowLayout的类在这个类当中写几条属性.

@property (strong, nonatomic) UILabel*priceLbl;@end////CollectionCell.m//CollectionView////Created by Piosa on 14-6-13.//Copyright (c) 2014年 D2space. All rights reserved.//#import"CollectionCell.h"@implementationCollectionCell- (id)initWithFrame:(CGRect)frame{self=[super initWithFrame:frame];if(self){self.imageView=[[UIImageView alloc]init];[selfaddSubview:self.imageView];//--------------//透明栏//--------------floath=30;floatx=0;floatw=CGRectGetWidth(frame);floaty=0;self.bottomBar=[[UIImageView alloc]initWithFrame:CGRectMake(x, y, w, h)];[selfaddSubview:self.bottomBar];self.bottomBar.image=[UIImage imageNamed:@"toumingse.png"];//产品名y=0;floattempH=h/2;x=3;self.productNameLbl=[[CBAutoScrollLabel alloc]initWithFrame:CGRectMake(x, y, w, tempH)];self.productNameLbl.backgroundColor=[UIColor clearColor];[self.bottomBar addSubview:self.productNameLbl];//产品价格y+=tempH;self.priceLbl=[[UILabel alloc]initWithFrame:CGRectMake(x, y, w, tempH)];self.priceLbl.textColor=[UIColor whiteColor];self.priceLbl.backgroundColor=[UIColor clearColor];self. priceLbl.font=[UIFont systemFontOfSize:12];[self.bottomBar addSubview:self.priceLbl];}returnself;}@end二.创建自定义布局#import#pragmamark WaterF@protocolWaterFLayoutDelegate @required- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;

@interface WFCollectionViewLayout : UICollectionViewLayout/** 指定有多少列. */@property (nonatomic, assign) NSInteger columnCounts;/** 设置距离屏幕四周的边界. */@property (nonatomic, assign) UIEdgeInsets edgeInsets;/** 列间距. */@property (nonatomic, assign) NSInteger columnSpace;/** 行间距. */@property (nonatomic, assign) NSInteger rowSpace;@property (nonatomic, assign)id<WFCollectionLayoutDelegate>delegate;@end

MyLayout*layout=[[MyLayout alloc]init];collectionView=[[UICollectionView alloc]initWithFrame:CGRectMake(0,0, CGRectGetWidth(self.frame),CGRectGetHeight(self.frame)) collectionViewLayout:layout];collectionView.delegate=self;collectionView.dataSource=self;collectionView.scrollEnabled=YES;[selfaddSubview:collectionView];collectionView.backgroundColor=[UIColor clearColor];[collectionView registerClass:[CollectionCellclass] forCellWithReuseIdentifier:@"CollectionCell"];3.实现代理#pragma-mark UICollectionView delegate//根据传入的图片得到宽高-(CGSize)getImgSize:(UIImage *)image{//得到比例floatrate=(itemWidth/image.size.width);returnCGSizeMake(itemWidth, (image.size.height*rate));

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.picArray.count;// 装数据的数组}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { WFPIcsCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"picsCell" forIndexPath:indexPath]; WFPhotosModel *photoModel = self.picArray[indexPath.row]; cell.photoModel = photoModel; return cell;}- layout:(WFCollectionViewLayout *)layout heightFroItenAtIndexPath:(NSIndexPath *)indexPath Width:widthh { WFPhotosModel *model = self.picArray[indexPath.row]; CGFloat height = widthh * model.height / model.width; return height;}

}//定义每个UICollectionView 的大小- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{NSDictionary*item=productList[indexPath.row];return[selfgetImgSize:[item objectForKey:KEY_PRODUCT_IMG]];}//定义每个UICollectionView 的 margin-(UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{returnUIEdgeInsetsMake(5,5,5,5);

在初始化方法中初始化数组.

@optional- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout heightForHeaderInSection:(NSInteger)section;- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout heightForFooterInSection:(NSInteger)section;@end@interfaceMyLayout : UICollectionViewLayout{floatx;floatleftY;floatrightY;

一.自定义UICollectionViewCell

- collectionViewContentSize { /** 滚动范围最长作为依据. */ __block NSString *maxY = @"0"; [self.columnDic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { if ([obj floatValue] > [self.columnDic[maxY] floatValue]) { maxY = key; } }]; CGFloat h = [self.columnDic[maxY] floatValue] + self.edgeInsets.bottom; return CGSizeMake;}

#pragma mark - 创建瀑布流 - createCollectionView { WFCollectionViewLayout *layout = [[WFCollectionViewLayout alloc] init]; layout.columnCounts = 2; layout.columnSpace = 20; layout.rowSpace = 15; layout.edgeInsets = UIEdgeInsetsMake(10, 10, 10, 10); layout.delegate = self; _picCollectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 20, SCREEN_WIDTH, SCREEN_HEIGHT - 68-44) collectionViewLayout:layout]; [self.view addSubview:_picCollectionView]; [_picCollectionView release]; _picCollectionView.delegate = self; _picCollectionView.dataSource = self; [_picCollectionView registerClass:[WFPIcsCell class] forCellWithReuseIdentifier:@"picsCell"]; 

}

4.重写自定义方法

@property (strong, nonatomic)  UIImageView*imageView;

当我们要对瀑布流添加下拉,上拉刷新的时候一定要将存储布局属性的数组进行清空.否则程序会crash.

@property (strong, nonatomic)  UICollectionView*collectionView;2.初始化

}-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{NSLog(@"indexPath=%d",indexPath.row);NSDictionary*item=productList[indexPath.row];DetailViewController*detailView=[[DetailViewController alloc]init];detailView.productID=[[item objectForKey:PRODUCT_ID] integerValue];[viewController.navigationController pushViewController:detailView animated:YES]; }//每个section的item个数-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{returnproductList.count;

}-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect{x=0;leftY=0;rightY=0;NSMutableArray* attributes =[NSMutableArrayarray];NSLog(@"cellCount=%d",self.cellCount);for(NSInteger i=0; i

本文由java编程发布,转载请注明来源:用collectionView做瀑布流,布局贰个collectionView瀑布