封装了一个iOS多分区自适应宽度layout

首先看效果图

实现的思路,支持配置代理,通过代理方式设置

每个item的frame,支持设置头部的size,

支持多个分区,之前做过类似的,但是只支持一个分区,

后来遇到过几次多分区的,都是将一个collectionView放到tableViewCell 中实现的,这次为了使layout更强大,支持了多

个分区的,思路就是我们在prepare layout 获取到

分区数量和每个分区cell数量

,然后创建对应的布局属性,添加到一个总的数组中

然后在系统方法中返回整个数组即可

复制代码
//
//  LBMutilMutilAutoWidthLayout.m
//  TEXT
//
//  Created by mac on 2025/3/30.
//

#import "LBMutilMutilAutoWidthLayout.h"

@interface LBMutilMutilAutoWidthLayout ()

@property (nonatomic, strong) NSMutableArray<UICollectionViewLayoutAttributes *> *layoutAttributesArray;

@property (nonatomic, assign) CGSize contentSize;

@end

@implementation LBMutilMutilAutoWidthLayout

- (instancetype)init {
    if (self = [super init]) {
        self.layoutAttributesArray = [NSMutableArray new];
    }
    return self;
}

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

- (CGSize)collectionViewContentSize {
    return self.contentSize;
}

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

#pragma mark - ---------- update ----------

- (void)updateLayout {
    // 移除旧的布局
    [self.layoutAttributesArray removeAllObjects];
    CGFloat currentY = 0;
    CGFloat x = self.sectionInset.left;
    // 计算新的布局
    NSInteger sectionCount = [self.collectionView numberOfSections];
    for (int i = 0; i < sectionCount; i ++) {
        CGSize headerSize = CGSizeZero;
        if (self.delegate && [self.delegate respondsToSelector:@selector(sizeForHeaderViewAtSection:)]) {
            headerSize = [self.delegate sizeForHeaderViewAtSection:i];
        }
        if (!CGSizeEqualToSize(headerSize, CGSizeZero)) {
            UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]];;
            layoutAttributes.frame = CGRectMake(0, currentY, headerSize.width, headerSize.height);
            currentY += headerSize.height;
            [self.layoutAttributesArray addObject:layoutAttributes];
        }
        NSInteger count = 0;
        if ([self.collectionView.dataSource respondsToSelector:@selector(collectionView:numberOfItemsInSection:)]) {
            count = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0];
        }
        CGFloat currentX = x;

        if (count > 0) {
            for (int j = 0; j < count; j++) {
                CGSize cellSize = [self sizeForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
                CGFloat cellWidth = cellSize.width;
                CGFloat cellHeight = cellSize.height;
                // 创建布局属性
                UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
                layoutAttributes.frame = CGRectMake(currentX, currentY, cellWidth, cellHeight);
                [self.layoutAttributesArray addObject:layoutAttributes];
                currentX += (self.minimumInteritemSpacing + cellWidth);
                // 计算下一个item的x,以及布局更新结束检测
                if (j != count - 1) {
                    if (currentX + cellWidth + self.minimumInteritemSpacing + self.sectionInset.right > self.contentWidth) {
                        currentX = self.sectionInset.left;
                        currentY += self.minimumLineSpacing + cellHeight;
                    }
                } else {
                    currentY += cellHeight;
                }
                if (i == sectionCount - 1 && j == count - 1) {
                    self.contentSize = CGSizeMake(self.contentWidth, currentY);
                }
            }
        }
    }
}

- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)index {
    CGSize size = CGSizeZero;
    if ([self.delegate respondsToSelector:@selector(sizeForItemAtIndexPath:)]) {
        size = [self.delegate sizeForItemAtIndexPath:index];
    }
    return size;
}

@end

用法

复制代码
//
//  LBMutilSecionAutoLayoutViewController.m
//  TEXT
//
//  Created by mac on 2025/3/30.
//

#import "LBMutilSecionAutoLayoutViewController.h"
#import "LBMutilMutilAutoWidthLayout.h"

@interface LBMutilSecionAutoLayoutViewController () <LBMutilMutilAutoWidthLayouttDelegate,
UICollectionViewDelegate,
UICollectionViewDataSource>

@property (nonatomic, strong) UICollectionView *collectionView;

@end

@implementation LBMutilSecionAutoLayoutViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view addSubview:self.collectionView];
    // Do any additional setup after loading the view.
}

#pragma mark - UICollectionViewDelegate,UICollectionViewDataSource

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"22" forIndexPath:indexPath];
    cell.contentView.backgroundColor = [UIColor cyanColor];
    return cell;
}

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
    UICollectionReusableView *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"header" forIndexPath:indexPath];
    return header;
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
   return 3;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

{
    return 10;
}
#pragma mark - LBMutilMutilAutoWidthLayouttDelegate

- (CGSize)sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CGFloat width;
    if (indexPath.section == 0) {
        width = 100;
        if (indexPath.item %2 == 0) {
            width = 50;
        }
        
    } else {
        width = 70;
        if (indexPath.item %2 == 0) {
            width = 30;
        }
    }
    
    return CGSizeMake(width, 20);
}

- (CGSize)sizeForHeaderViewAtSection:(NSInteger)section
{
    return CGSizeMake(375, 40);
}

#pragma mark  - lazy load

- (UICollectionView *)collectionView
{
    if (!_collectionView) {
        LBMutilMutilAutoWidthLayout *layout = [[LBMutilMutilAutoWidthLayout alloc] init];
        layout.delegate = self;
        layout.contentWidth = 375;
        layout.minimumInteritemSpacing = 10;
        layout.sectionInset = UIEdgeInsetsZero;
        _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 100, 375, 400) collectionViewLayout:layout];
        _collectionView.dataSource = self;
        _collectionView.delegate = self;
        [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"22"];
        [_collectionView registerClass:[UICollectionReusableView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"header"];
    }
    return _collectionView;
}

@end
相关推荐
2501_916008891 小时前
深入解析iOS机审4.3原理与混淆实战方法
android·java·开发语言·ios·小程序·uni-app·iphone
忆江南2 小时前
Flutter深度全解析
ios
山水域2 小时前
Swift 6 严格并发检查:@Sendable 与 Actor 隔离的深度解析
ios
楚轩努力变强3 小时前
iOS 自动化环境配置指南 (Appium + WebDriverAgent)
javascript·学习·macos·ios·appium·自动化
猫头虎19 小时前
如何解决 OpenClaw “Pairing required” 报错:两种官方解决方案详解
网络·windows·网络协议·macos·智能路由器·pip·scipy
游戏开发爱好者81 天前
日常开发与测试的 App 测试方法、查看设备状态、实时日志、应用数据
android·ios·小程序·https·uni-app·iphone·webview
黑码哥1 天前
ViewHolder设计模式深度剖析:iOS开发者掌握Android列表性能优化的实战指南
android·ios·性能优化·跨平台开发·viewholder
2501_915106321 天前
app 上架过程,安装包准备、证书与描述文件管理、安装测试、上传
android·ios·小程序·https·uni-app·iphone·webview
2501_915106321 天前
使用 Sniffmaster TCP 抓包和 Wireshark 网络分析
网络协议·tcp/ip·ios·小程序·uni-app·wireshark·iphone
熊猫钓鱼>_>1 天前
移动端开发技术选型报告:三足鼎立时代的开发者指南(2026年2月)
android·人工智能·ios·app·鸿蒙·cpu·移动端