美文网首页
自定义UICollectionViewLayout

自定义UICollectionViewLayout

作者: 不务正业Darwin | 来源:发表于2016-08-13 00:03 被阅读0次

CollectionView的组成

  • cells
  • Supplementary Views 追加视图,(类似于header和footer)
  • Decoration Views 装饰视图

UICollectionViewLayoutAttributes

UICollectionViewLayoutAttributes

property列表:

//边框
@property (nonatomic) CGRect frame
//中心点
@property (nonatomic) CGPoint center
//大小
@property (nonatomic) CGSize size
//形状
@property (nonatomic) CATransform3D transform3D
//透明度
@property (nonatomic) CGFloat alpha
//层次
@property (nonatomic) NSInteger zIndex
//隐藏
@property (nonatomic, getter=isHidden) BOOL hidden

自定义UICollectionViewLayout

-(CGSize)collectionViewContentSize
//返回collectionView的内容的尺寸

-(NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
//返回rect中的所有的元素的布局属性
//可以通过不同方法获得cell,追加视图,装饰视图的属性

-(UICollectionViewLayoutAttributes _)layoutAttributesForItemAtIndexPath:(NSIndexPath _)indexPath
//返回对应于indexPath的位置的cell的布局属性

-(UICollectionViewLayoutAttributes _)layoutAttributesForSupplementaryViewOfKind:(NSString _)kind atIndexPath:(NSIndexPath *)indexPath
//返回对应于indexPath的位置的追加视图的布局属性,如果没有追加视图可不重载

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
//当边界发生改变时,是否应该刷新布局。如果YES则在边界变化(一般是scroll到其他地方)时,将重新计算需要的布局信息

实例化一个UICollectionViewLayout后,-(void)prepareLayout将被调用,默认的情况下不做什么工作,自己实现时设定一些必要的layout结构和初始化参数。

下面是一个Demo

layout的.h文件

//高度代理
@class LFCLayout;
@protocol LFCCellHeightDelegate <NSObject>
-(CGFloat)LFCLayout:(LFCLayout*)layout cellHeightAtIndexPath:(NSIndexPath*)indexPath;
@end

@interface LFCLayout : UICollectionViewLayout
//行间距
@property (nonatomic,assign) CGFloat rowPadding;
//列间距
@property (nonatomic,assign) CGFloat colPadding;
//列数
@property (nonatomic,assign) CGFloat colNum;
//collectionView contentSize
@property (nonatomic,assign) CGSize contentSize;

@property (nonatomic,assign) UIEdgeInsets sectionInsets;

@property (nonatomic,weak) id<LFCCellHeightDelegate> delegate;

@end

.m文件

-(void)prepareLayout{
    [super prepareLayout];
    
    if (self.attributes == nil) {
        self.attributes = [NSMutableArray array];
    }
    
    if (self.heightOfColArray == nil) {
        self.heightOfColArray = [NSMutableArray array];
    }
    
    RowPadding = self.rowPadding == 0 ? RowPadding : self.rowPadding;
    ColPadding = self.colPadding == 0 ? ColPadding : self.colPadding;
    ColNum = self.colNum == 0 ? ColNum : self.colNum;
    edge = self.sectionInsets;
    
    //初始化每一列的高度
    [self.heightOfColArray removeAllObjects];
    for (NSInteger i = 0; i < ColNum; i++) {
        [self.heightOfColArray addObject:@(edge.top)];
    }
    
    //获取layoutattribute
    NSInteger count = [self.collectionView numberOfItemsInSection:0];
    for (NSInteger i = 0; i < count; i++) {
        NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        UICollectionViewLayoutAttributes* attribute = [self layoutAttributesForItemAtIndexPath:indexPath];
        [self.attributes addObject:attribute];
    }
}
//返回对应于indexPath的位置的cell的布局属性
-(UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
    UICollectionViewLayoutAttributes* attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    
    //定义每个cell的宽和高
    CGFloat width = (self.collectionView.bounds.size.width - edge.left - edge.right - (ColNum - 1) * RowPadding) / ColNum;
    CGFloat height = 0;
    
    //判断delegate对象是否有该名字的方法,返回每个cell的高度
    if ([self.delegate respondsToSelector:@selector(LFCLayout:cellHeightAtIndexPath:)]) {
        height = [self.delegate LFCLayout:self cellHeightAtIndexPath:indexPath];
    }
    
    //默认第一列高度最低
    CGFloat minY = self.heightOfColArray.count ? [[self.heightOfColArray firstObject] floatValue] : edge.top;
    //找出高度最低的那一列
    NSInteger currentLow = 0;
    for (NSInteger i = 1; i < self.heightOfColArray.count; i++) {
        if (minY > [self.heightOfColArray[i] floatValue]) {
            minY = [self.heightOfColArray[i] floatValue];
            currentLow = i;
        }
    }
    
    //找出之后即可定义每个cell的坐标位置以及大小
    CGFloat x = edge.left + (width + RowPadding) * currentLow;
    CGFloat y = minY + edge.top;
    attribute.frame = CGRectMake(x, y, width, height);
    
    self.heightOfColArray[currentLow] = @(CGRectGetMaxY(attribute.frame));
    //找出最高的一列的高度,设定contentSize;
    CGFloat maxY = self.heightOfColArray.count ? [[self.heightOfColArray firstObject] floatValue] : edge.top;
    for (NSInteger i = 1; i < self.heightOfColArray.count; i++) {
        if (maxY < [self.heightOfColArray[i] floatValue]) {
            maxY = [self.heightOfColArray[i] floatValue];
        }
    }
    
    self.contentSize = CGSizeMake(self.collectionView.bounds.size.width, maxY + edge.bottom);
    
    return attribute;
}

之前的Demo的图片为同步加载
cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]];,所以scroll会有卡顿,将图片改为异步加载,并且在第一次加载后将其放置在本地,再次取用时直接从本地取用。


菜鸟刚刚起步。。。参考其他人代码,然后自己自己加了注解敲了一遍
如有错误的地方希望大家可以指正。
[GitHub]https://github.com/superLFC/CollectionViewLayoutDemo

相关文章

网友评论

      本文标题:自定义UICollectionViewLayout

      本文链接:https://www.haomeiwen.com/subject/uiuesttx.html