iOS collectionView不同分区配置不同的装饰视图 DecorationView

达到的效果如图,纯图片分区和其他分区使用不同的装饰视图,下面的是白色装饰视图哦

首先,要自定义一个layout, 然后,在初始化Layout的时候注册装饰视图

如图

需要注意的一点,创建装饰视图的过程是在创建装饰视图布局属性的时候系统完成的,

所以,我们在代码中看不到返回装饰视图的地方

我们如果要在某个分区使用某个视图,需要创建装饰视图的布局属性的时候,使用注册该装饰视图的kind即可,如图

这里kind和装饰视图是一一对应的,相当于cell 的identifier

这里使用代理,支持不同分区配置不同类型的装饰视图

附上代码

//
//  VVCollectionDecorationLayout.h
//  VOVA
//
//  Created by 刘博 on 2020/11/11.
//  Copyright © 2020 iOS. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef UIEdgeInsets(^DecorationExtendEdges)(NSInteger section);

NS_ASSUME_NONNULL_BEGIN

@protocol VVCollectionDecorationLayoutDelegte <NSObject>

- (Class)decorationViewClassOfSection:(NSInteger)section;

@end

@interface VVCollectionDecorationLayout : UICollectionViewFlowLayout

/// 装饰视图的边距默认 UIEdgeInsetZero
@property (nonatomic, copy) DecorationExtendEdges decorationExtendEdges;

///适配头部和尾部布局,头部和尾部的布局 用到 分区的edgeInset和 装饰视图的 edgeInset ,默认为NO
@property (nonatomic, assign) BOOL adjustHeaderAndFooterLayout;

装饰视图范围包含头部,默认NO
@property (nonatomic, assign) BOOL decorationContainsHeader;

@property (nonatomic, weak) id <VVCollectionDecorationLayoutDelegte> vvDelegate;

@end

NS_ASSUME_NONNULL_END
//
//  VVCollectionDecorationLayout.m
//  VOVA
//
//  Created by 刘博 on 2020/11/11.
//  Copyright © 2020 iOS. All rights reserved.
//

#import "VVCollectionDecorationLayout.h"
#import "VVCategoryBannerDecorationView.h"
#import <vv_bodylib_ios/VVBaseCollectionDecorationView.h>


@interface VVCollectionDecorationLayout ()

///装饰视图布局属性数组
@property (nonatomic, copy) NSArray<UICollectionViewLayoutAttributes *> * decorationViewAttrs;

@end

@implementation VVCollectionDecorationLayout

- (void)prepareLayout {
    [super prepareLayout];
    [self caculateDecorationLayoutAttributes];
}

- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray<UICollectionViewLayoutAttributes *> *originAttrs = [super layoutAttributesForElementsInRect:rect];
    if (self.adjustHeaderAndFooterLayout) {
        ///适配头部,需要修改头部视图布局
        // if use NSEnumerationConcurrent, get main thread warning: Main Thread Checker: UI API called on a background thread: -[UIScrollView delegate]
        [originAttrs enumerateObjectsWithOptions:0 usingBlock:^(UICollectionViewLayoutAttributes * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            
            if ([obj.representedElementKind isEqualToString:UICollectionElementKindSectionHeader] || [obj.representedElementKind isEqualToString:UICollectionElementKindSectionFooter]) {
                
                // get section insets
                UIEdgeInsets sectionInsets = UIEdgeInsetsZero;
                if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
                    sectionInsets = [(id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:obj.indexPath.section];
                }
                else {
                    sectionInsets = self.sectionInset;
                }
                
                // get extend insets
                UIEdgeInsets decorationInsets = self.decorationExtendEdges ? self.decorationExtendEdges(obj.indexPath.section): UIEdgeInsetsZero;
                
                CGRect frame = obj.frame;
                if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
                    if (IS_RightToLeft) {
                        ///适配反向布局
                        frame.origin.x += (sectionInsets.right - decorationInsets.right);
                    } else {
                        frame.origin.x += (sectionInsets.left - decorationInsets.left);
                    }
                    frame.size.width -= (sectionInsets.left + sectionInsets.right - decorationInsets.left - decorationInsets.right);
                } else {
                    frame.origin.y += (sectionInsets.top - decorationInsets.top);
                    frame.size.height -= (sectionInsets.top + sectionInsets.bottom - decorationInsets.top - sectionInsets.bottom);
                }
                obj.frame = frame;
            }
        }];
    }
    
    NSMutableArray *mut_originAttrs = originAttrs.mutableCopy;
    [mut_originAttrs addObjectsFromArray:self.decorationViewAttrs];
    
    return mut_originAttrs.copy;
}

///计算装饰视图布局属性
- (void)caculateDecorationLayoutAttributes {
    NSInteger numberOfSections = [self.collectionView numberOfSections];
    if (numberOfSections > 0) {
        NSMutableArray *decorationViewsAttrs = [NSMutableArray arrayWithCapacity:numberOfSections];
        if (self.vvDelegate && [self.vvDelegate respondsToSelector:@selector(decorationViewClassOfSection:)]) {
            for (NSInteger section = 0; section < numberOfSections; section++) {
                Class decorationViewClass = [self.vvDelegate decorationViewClassOfSection:section];
                NSIndexPath *firstItemIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
                UICollectionViewLayoutAttributes *decorationViewAttr ;
                if ([decorationViewClass isSubclassOfClass:[VVBaseCollectionDecorationView class]]
                    && [decorationViewClass respondsToSelector:@selector(kind)]) {
                    decorationViewAttr =  [UICollectionViewLayoutAttributes layoutAttributesForDecorationViewOfKind:[decorationViewClass kind] withIndexPath:firstItemIndexPath];
                    decorationViewAttr.frame = [self decrationViewFrameForSection:section];
                    decorationViewAttr.zIndex = -1;
                    [decorationViewsAttrs addObject:decorationViewAttr];
                }
            }
        }
        self.decorationViewAttrs = decorationViewsAttrs;
    }
}

///创建某个分区的装饰视图布局
- (CGRect)decrationViewFrameForSection:(NSInteger)section {
    CGRect decrationFrame = CGRectZero;
    
    NSInteger sectionItemCount = [self.collectionView numberOfItemsInSection:section];
    if (sectionItemCount == 0) {
        return decrationFrame;
    }
    
    UICollectionViewLayoutAttributes *firstItemAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    UICollectionViewLayoutAttributes *lastItemAttr = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:(sectionItemCount - 1) inSection:section]];

    if (self.decorationContainsHeader) {
        ///装饰视图范围包含头部的时候,需要从头部开始
        firstItemAttr = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:section]];
    }
    
    CGRect firstItemFrame = firstItemAttr.frame;
    CGRect lastItemFrame = lastItemAttr.frame;
    
    UIEdgeInsets sectionInsets = UIEdgeInsetsZero;
    if ([self.collectionView.delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]) {
        sectionInsets = [(id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate collectionView:self.collectionView layout:self insetForSectionAtIndex:section];
    }
    else {
        sectionInsets = self.sectionInset;
    }
    
    decrationFrame.origin.x = firstItemFrame.origin.x;
    if (self.decorationContainsHeader) {
        ///包含头部的话需要以头部为准
        UIEdgeInsets decorationInsets = self.decorationExtendEdges?self.decorationExtendEdges(section):UIEdgeInsetsZero;
        decrationFrame.origin.x += (sectionInsets.left - decorationInsets.left);

    }
    if (IS_RightToLeft) {
        //适配反向布局
        decrationFrame.origin.x = sectionInsets.right;
    }
    decrationFrame.origin.y = firstItemFrame.origin.y;
    if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
        decrationFrame.size.height = CGRectGetMaxY(lastItemFrame) - firstItemFrame.origin.y;
        decrationFrame.size.width = CGRectGetWidth(self.collectionView.bounds) - sectionInsets.left - sectionInsets.right;
    } else {
        decrationFrame.size.height = CGRectGetHeight(self.collectionView.bounds) - sectionInsets.top - sectionInsets.bottom;
        decrationFrame.size.width = CGRectGetMaxX(lastItemFrame) - firstItemFrame.origin.x;
    }
    
    UIEdgeInsets insets = self.decorationExtendEdges ? self.decorationExtendEdges(section): UIEdgeInsetsZero;
    if (!UIEdgeInsetsEqualToEdgeInsets(insets, UIEdgeInsetsZero)) {
        decrationFrame.origin.x -= insets.left;
        if (IS_RightToLeft) {
            decrationFrame.origin.x -= insets.right;
        }
        decrationFrame.origin.y -= insets.top;
        decrationFrame.size.width += (insets.left + insets.right);
        decrationFrame.size.height += (insets.top + insets.bottom);
    }
    
    return decrationFrame;
}

@end

demo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
iOSCollectionView是一种强大的界面展示控件,它允许我们展示多个横向或纵向滚动的项。而Section Header是CollectionView中的一个重要组成部分,它可以用来展示每个分区的标题或其他相关信息。 在iOS中使用CollectionView的时候,我们可以通过实现UICollectionViewDelegateFlowLayout协议来设置每个分区的大小、间距等布局属性。而Section Header则需要通过实现UICollectionViewDelegate的collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法来自定义。 首先,我们需要创建一个UICollectionReusableView类的子类作为Section Header的视图。然后,在collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法中,我们需要判断elementKind是否为UICollectionElementKindSectionHeader,并根据需要从重用队列中获取Section Header的视图对象。 接下来,我们可以设置Section Header的标题、背景色、字体颜色等视觉效果。例如,我们可以使用UILabel来展示标题,并通过设置UILabel的text属性来显示每个分区的标题。如果需要更加丰富的自定义效果,我们还可以使用自定义的视图来展示Section Header。 最后,我们需要在UICollectionViewFlowLayout中设置sectionHeadersPinToVisibleBounds属性为true,以便在滚动时固定Section Header的位置。这样,当用户滚动CollectionView时,Section Header会始终显示在顶部,增加了用户的使用体验。 综上所述,iOSCollectionView提供了强大的支持来展示多个滚动项,而Section Header则可以用来展示每个分区的相关信息。通过实现UICollectionViewDelegate的collectionView:viewForSupplementaryElementOfKind:atIndexPath:方法,我们可以自定义Section Header的视图,并通过UICollectionViewFlowLayout来设置其布局等属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值