欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【iOS】UICollectionView的装饰视图——decorationView

程序员文章站 2024-03-24 10:13:10
...

最近有一个新需求,需要给列表中每一个section单独加一个背景,如下:【iOS】UICollectionView的装饰视图——decorationView
这……用tableview做的想法在看到这个背景的时候就没了,人也傻了。百度了一下发现UICollectionView可以实现,就是使用decorationView,不过资料还蛮少的,都是13年左右,坑也有不少,自己先按着教程摸索着整了一个,记录一下。

先说一下流程:

  1. 创建一个继承自UICollectionReusableView的视图,这就是我们接下来要用的decorationView装饰视图,这里我命名为XY_RM_ListViewCollectionSectionDecorationView;
  2. 创建一个继承自UICollectionViewLayoutAttributes的类,这是装饰视图需要用到的Attributes,如果装饰视图需要根据不同的section设置不同的图片,就可以在这个类里添加属性来记录。我的需求中的背景很单一,就是一个view加了shadow,所以我使用的是UICollectionViewLayoutAttributes,并没有创建新类;
  3. 创建layout文件设置布局;

从第一步开始:创建一个继承自UICollectionReusableView的视图;

//初始化
-(instancetype)initWithFrame:(CGRect)frame{
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor whiteColor];
    }
    return self;
}

//加载Attributes
-(void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes{
    [super applyLayoutAttributes:layoutAttributes];
    [self.bgView removeFromSuperview];
    [self addSubview:self.bgView];
}

要调用apply方法来加载attributes,在这里设置你需要设置的内容,要注意decorationView会重用;

第二步我没有做,就不写了

第三步创建布局文件:

@protocol XY_RM_ListViewCollectionLayoutDelegate <NSObject>
//itemsize
-(CGSize)sizeOfItemForIndexPath:(NSIndexPath *)indexPath;
//表头高度
-(CGFloat)heightOfHeaderViewForIndexPath:(NSIndexPath *)indexPath;

@end


@interface XY_RM_ListViewCollectionLayout : UICollectionViewLayout

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

@property (nonatomic, strong) NSMutableArray *sectionSizeArray;   ///<每个section位置的数组

@end

这里定义了两个协议方法来获取itemSize和header的高度,同时定义了一个sectionSizeArray,这个数组储存每一个section的frame数据。

//初始化
-(instancetype)init{
    if (self = [super init]) {
        //注册装饰视图
        [self registerClass:[XY_RM_ListViewCollectionSectionDecorationView class] forDecorationViewOfKind:@"XY_RM_ListViewCollectionSectionDecorationView"];
    }
    return self;
}

decorationView比较特殊,是要在layout里面进行注册的,这里我们放在init里注册。

//开始布局
-(void)prepareLayout{
    //初始化
    self.totalHeight = 0.0;
    self.attArray = [NSMutableArray array];
    self.sectionSizeArray = [NSMutableArray array];
    
    //遍历section
    NSInteger sectionCount = [self.collectionView numberOfSections];
    for (int i=0; i<sectionCount; i++) {
        NSIndexPath *sectionIndexPath = [NSIndexPath indexPathWithIndex:i];
        //设置起点
        CGPoint startPoint = CGPointMake(0, self.totalHeight);
        //设置上内边距
        self.totalHeight += self.topSpace;
        //如果有高度,添加头部属性
        CGFloat height=0.0;
        if ([self.delegate respondsToSelector:@selector(heightOfHeaderViewForIndexPath:)]) {
            height = [self.delegate heightOfHeaderViewForIndexPath: sectionIndexPath];
        }
        if (height>0.0) {
            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:sectionIndexPath];
            [self.attArray addObject:attributes];
        }
        
        //头部添加完添加当前section中item的属性
        NSInteger itemsCount = [self.collectionView numberOfItemsInSection:i];
        self.x = 0.0;
        self.y = self.totalHeight;
        for (int j=0; j<itemsCount; j++) {
            NSIndexPath *itemIndexPath = [NSIndexPath indexPathForItem:j inSection:i];
            //添加item的属性
            UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
            [self.attArray addObject:attributes];
            //如果是这个section最后一个,修改total
            if (j == itemsCount-1) {
                self.totalHeight = CGRectGetMaxY(attributes.frame)+self.bottomSpace;
                //保存终点
                CGPoint endPoint = CGPointMake(CGRectGetMaxX(attributes.frame), self.totalHeight);
                //设置section的frame
                CGRect rect = CGRectMake(startPoint.x, startPoint.y, endPoint.x-startPoint.x, endPoint.y-startPoint.y);
                //保存
                [self.sectionSizeArray addObject:NSStringFromCGRect(rect)];
                //添加装饰att
                UICollectionViewLayoutAttributes *attri = [self layoutAttributesForDecorationViewOfKind:@"" atIndexPath:sectionIndexPath];
                [self.attArray addObject:attri];
            }
        }
    }
}

计算sectionframe我是使用point的方式,在header之前记录startpoint,在section中最后一个item之后记录endpoint,section的size就是两点相减,将rectString添加进sectionSizeArray;

-(UICollectionViewLayoutAttributes *)layoutAttributesForDecorationViewOfKind:(NSString *)elementKind atIndexPath:(NSIndexPath *)indexPath{
    //获取属性
    UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:@"XY_RM_ListViewCollectionSectionDecorationView" withIndexPath:indexPath];
    //设置frame
    NSString *rectString = [self.sectionSizeArray objectAtIndex: indexPath.section];
    CGRect frame = CGRectFromString(rectString);
    attributes.frame = frame;
    //纵向坐标调整到底下
    attributes.zIndex = -1;
    
    return attributes;
}

zIndex这个属性调整collectionview中的层级关系,cell是0,要想装饰视图在cell底部,就要把装饰视图的zindex调整到小于0;

到目前为止就ok了,运行就能看见上图效果

相关标签: iosUI ios