CollectionView和layout的使用,瀑布流

1 .CollectionView

CollectionView是tableView的升级版,可以理解为多列的tableView,用法也tableView也基本相同,但也有不同的

CollectionViewCell和TableViewCell一样,有cell,只是这里叫Item,我们可以规定Item的位置,但是这里item默认不具有cell的三大属性(imageView,textLabel,detailTextLabel),因此在设置cell的这些设置时,我们可以采用自定义MyCollectionViewCell,在这设置这些属性即可

2 .layout  --- 也叫布局

UICollectionViewLayout是一个基类,是所有的布局文件的父类,但是里面并没有元素位置的定义

UICollectionViewFlowLayout是上面的一个子类,他实现了元素位置的定义,实现了流水式布局

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayoutalloc]init];

    // 设置每一个元素的大小

    layout.itemSize =CGSizeMake(100,100);

    //  设置内边距大小

    layout.sectionInset =UIEdgeInsetsMake(20,20, 40, 20);

    //  设置滚动方向

//    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    //  设置最小行间距

    layout.minimumLineSpacing =50;

    //  设置最小列间距

    layout.minimumInteritemSpacing =10;

   //  行间距的设置一定会实现,列间距的设置不一定会实现,因为存在剩余空间的平均分配问题

   //  行间距因滚动方向的不同作用的效果方向也不同.

    self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:layout];

    [selfaddSubview:self.collection];

我们还可以在RootViewController对connection设置代理为当前controller,让代理调用方法,返回item的size
例如:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    if (indexPath.row %2) {

        return CGSizeMake(120, 120);

    } else {

        return CGSizeMake(80, 80);

    }

}


3 .瀑布流


如果我们想要实现瀑布流的效果,需要对每一个item的size根据对应的image进行比例缩放,如果用系统自带的layout难以实现这个要求,因此我们只需自定义layout,其他不改变即可

基于UICollectionViewLayout创建WaterFlowLayout

WaterFlowLayout.h

#import <UIKit/UIKit.h>


@protocol WaterFlowLayoutDelegate <NSObject>

// 通过indexPath位置的图片,根据图片的宽高的比例,以及itemwidth计算出indexPathitem的高度,最终通过在controller中指定代理,实现该方法

- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath;


@end


@interface WaterFlowLayout : UICollectionViewLayout


//  给自定义layout创建Layout所具备的以下几个属性

//  Item的大小,最主要的是根据这个获取到列宽

@property (nonatomic,assign) CGSize itemSize;

// 内边距的设置

@property (nonatomic,assign) UIEdgeInsets sectionInsets;

//  Item的间距

@property (nonatomic,assign) CGFloat spacing;

// 一共有几列

@property (nonatomic,assign) NSInteger numberOfColumns;

// 代理,用于绑定数据,计算高度的

@property (nonatomic,assign) id <WaterFlowLayoutDelegate>delegate;


@end




WaterFlowLayout.m

@interfaceWaterFlowLayout ()


//  保存一共有几个Item

@property (nonatomic,assign) NSInteger numberOfItems;

// 保存计算好的每一个item的位置信息

@property (nonatomic,strong) NSMutableArray *itemAttributes;

// 保存每一列的高度

@property (nonatomic,strong) NSMutableArray *columnsHeights;


// 找到当前最长列的标号

- (NSInteger)indexForHeightestColumn;

// 找到当前最短列的标号

- (NSInteger)indexForShortestColumn;


@end




@implementation WaterFlowLayout


// 懒加载属性值

- (NSMutableArray *)columnsHeights {

    if (_columnsHeights ==nil) {

        _columnsHeights = [NSMutableArrayarray];

    }

    return_columnsHeights;

}


- (NSMutableArray *)itemAttributes {

    if (_itemAttributes ==nil) {

        _itemAttributes = [NSMutableArrayarray];

    }

    return_itemAttributes;

}


- (NSInteger)indexForHeightestColumn {

    NSInteger index =0;

    //  记录最长的长度

    CGFloat length =0;

    for (int i =0; i < self.numberOfColumns; i++) {

        // 将数组里的对象转换成float类型的值

        CGFloat currentValue = [self.columnsHeights[i]floatValue];

        if (currentValue > length) {

            length = currentValue;

            index = i;

        }

    }

    return index;

}


- (NSInteger)indexForShortestColumn {

    NSInteger index =0;

    CGFloat length =MAXFLOAT;

    for (int i =0; i < self.numberOfColumns; i++) {

        CGFloat currentValue = [self.columnsHeights[i]floatValue];

        if (currentValue < length) {

            length = currentValue;

            index = i;

        }

    }

    return index;

}


// 准备布局,在这里计算每一个Itemframe

- (void)prepareLayout {

    [superprepareLayout];

   //  拿到一共有多少个元素

    self.numberOfItems = [self.collectionViewnumberOfItemsInSection:0];

    //  给每一列添加一个top的高度

    for (int i =0; i < self.numberOfColumns; i++) {

        self.columnsHeights[i] =@(self.sectionInsets.top)// NSNumber

    }

   //  挨个去为每一个元素创建属性信息,并存放到数组中

    for (int i =0; i < self.numberOfItems; i++) {

        //  1 确定元素高度最短列

        NSInteger shortestIndex = [selfindexForShortestColumn];

        //  2 拿到最短列的高度备用

        CGFloat height = [self.columnsHeights[shortestIndex]floatValue];

        //  3 计算x的值  目标x = 内边距的左边距 + ( + Item间距) *列数

        CGFloat detalX =self.sectionInsets.left + (self.itemSize.width + self.spacing) * shortestIndex;

        //  4 计算y的值

        CGFloat detalY = height +self.spacing;

        //  5 创建属性

        NSIndexPath *indexPath = [NSIndexPathindexPathForItem:i inSection:0];

        UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributeslayoutAttributesForCellWithIndexPath:indexPath];

        //  6 调用代理计算高度

        CGFloat itemHeight =0;

        if (_delegate && [_delegaterespondsToSelector:@selector(heightForItemIndexPath:)]) {

            //  计算高度

            itemHeight = [_delegateheightForItemIndexPath:indexPath];

        }

        //  7 生成frame

        attributes.frame =CGRectMake(detalX, detalY, self.itemSize.width, itemHeight);

        //  8 将这个信息对象放到数组里面

        [self.itemAttributesaddObject:attributes];

        //  9 更新这一列的高度

        self.columnsHeights[shortestIndex] =@(detalY + itemHeight);

    }

}


//  返回contentView的大小

- (CGSize)collectionViewContentSize{

    //  求最高列的高度

    NSInteger longestIndex = [selfindexForHeightestColumn];

    CGFloat height = [self.columnsHeights[longestIndex]floatValue];

    //  拿到contentView的原始大小

    CGSize size =self.collectionView.frame.size;

    size.height = height +self.sectionInsets.bottom;

    return size;

}


//  返回每一个ItemAttributes(属性信息)

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {

    returnself.itemAttributes;

    

}


@end



创建完自定义Layout,就可以利用此WaterFlowLayout创建瀑布流的专属Layout

RootView.m

//  使用瀑布流的专属Layout

    self.layout = [[WaterFlowLayoutalloc] init];

    //  设置属性

    CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;

    self.layout.itemSize =CGSizeMake(w, 10);

    //  内边距

    self.layout.sectionInsets =UIEdgeInsetsMake(10,10, 10, 10);

    // item 间距

    self.layout.spacing =10;

    //  一共有几列

    self.layout.numberOfColumns =3;


    self.collection = [[UICollectionViewalloc] initWithFrame:[UIScreenmainScreen].boundscollectionViewLayout:self.layout];

    [selfaddSubview:self.collection];



RootViewController.m

接受WaterFlowLayout中的代理,并指定代理为当前controller

实现代理中的方法

- (CGFloat)heightForItemIndexPath:(NSIndexPath *)indexPath {

    //  拿到model

    Model *m = self.data[indexPath.item];

    //  获取图片宽度

    CGFloat w = ([UIScreenmainScreen].bounds.size.width -40) / 3;

    CGFloat h = (w * m.height) / m.width;

    return h;

}


model.h

#import <Foundation/Foundation.h>


@interface Model : NSObject

@property (nonatomic,copy) NSString *thumbURL;

@property (nonatomic,assign) NSInteger width;

@property (nonatomic,assign) NSInteger height;

@end


model.m中  

如果解析时用到添加字典到model

不要忘记 !!!  

@implementation Model


- (void)setValue:(id)value forUndefinedKey:(NSString *)key {


}


@end

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值