UICollectionViewCell自适应宽度

2023-05-16

在这里插入图片描述

如图所示效果,根据字符长度自适应UICollectionViewCell的大小,同时进行左对齐处理。

如何实现
继承UICollectionViewFlowLayout创建子类,并实现相关的方法,如:

1、- (void)prepareLayout;
2、- (CGSize)collectionViewContentSize;
3、- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect;

具体怎么编码实现
代码示例如下:
1、UICollectionViewFlowLayout子类
.h文件

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@protocol CollectionLayoutDelegate <NSObject>

/// 获取item高度
- (CGFloat)widthForItemIndexPath:(NSIndexPath *)indexPath AndCollectioinView:(UICollectionView *)collectionView;

@end

@interface CollectionLayout : UICollectionViewFlowLayout

@property (nonatomic, weak) id<CollectionLayoutDelegate>delegate;
/// 视图宽
@property (nonatomic, assign) CGFloat layoutWidth;
/// 自适应collection的大小(默认NO)
@property (nonatomic, assign) BOOL autoContentSize;

@end

.m文件

#import "CollectionLayout.h"

@interface CollectionLayout ()

// 临时保存item的总宽度
@property (nonatomic, assign) CGFloat columnWidth;
// 记录一共有多少行
@property (nonatomic, assign) NSInteger columnNumber;
// 保存每一个item x y w h
@property (nonatomic, retain) NSMutableArray *arrForItemAtrributes;
// 保存item总数
@property (nonatomic,assign) NSUInteger numberOfItems;
// 保存每个item的X值
@property (nonatomic, assign) CGFloat xForItemOrigin;
// 保存每个item的Y值
@property (nonatomic, assign) CGFloat yForItemOrigin;

@end


@implementation CollectionLayout

// 准备布局
- (void)prepareLayout
{
    [super prepareLayout];
    //
    self.columnWidth = self.sectionInset.left;
    self.columnNumber = 0;
    self.arrForItemAtrributes = [NSMutableArray array];
    self.xForItemOrigin = self.sectionInset.left;
    self.yForItemOrigin = self.sectionInset.top;
    
    // 获取item的个数
    self.numberOfItems = [self.collectionView numberOfItemsInSection:0];
    /** 为每个item确定LayoutAttribute属性,同时将这些属性放入布局数组中 */
    for (int i = 0; i < self.numberOfItems; i++) {
        /** 确定每个Item的indexPath属性 */
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
        /** 确定每个item的origin的x,y值 */
        /** 确定每个Item的frame属性,同时确定了每个Item的LayoutAttribute,放入到了布局属性数组中 */
        [self setFrame:indexPath];
    }
}

// 计算contentView的大小
- (CGSize)collectionViewContentSize
{
    // 获取collectionView的Size
    CGSize contentSize = self.collectionView.frame.size;
    // 最大高度+bottom
    CGFloat height = self.sectionInset.top + (self.estimatedItemSize.height * (self.columnNumber + 1)) + (self.minimumLineSpacing * self.columnNumber) + self.sectionInset.bottom;
    contentSize.height = height;
    
    // 设置collectionView的大小自适应
    if (self.autoContentSize) {
        self.collectionView.frame = CGRectMake(self.collectionView.frame.origin.x, self.collectionView.frame.origin.y, contentSize.width, contentSize.height);
    }
    
    return contentSize;
}

// 返回每一个item的attribute
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    // 返回每一个item的Attribute
    return self.arrForItemAtrributes;
}

// 设置属性和frame
- (void)setFrame:(NSIndexPath *)indexPath
{
    // 设置Item LayoutAttribute 属性
    UICollectionViewLayoutAttributes *layoutArr = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
    // 获取item的高
    CGFloat itemWidth = 0;
    if (_delegate && [_delegate respondsToSelector:@selector(widthForItemIndexPath:AndCollectioinView:)]) {
        // 使用代理方法获取item的高
        itemWidth = [_delegate widthForItemIndexPath:indexPath AndCollectioinView:self.collectionView];
    }
    //之前item的宽总和 + 当前item的宽 + 间距 < 屏幕总款
    if (self.columnWidth + itemWidth + self.minimumInteritemSpacing < self.layoutWidth) {
        // 设置x
        self.xForItemOrigin = self.columnWidth;
        self.columnWidth += itemWidth + self.minimumInteritemSpacing;
    } else {
        self.xForItemOrigin = self.sectionInset.left;
        // 如果宽度超过屏幕从新计算宽度
        self.columnWidth = self.sectionInset.left + itemWidth + self.minimumInteritemSpacing;
        self.columnNumber++;
    }
    // 计算是第几行 乘以高度
    self.yForItemOrigin = self.sectionInset.top + (self.estimatedItemSize.height + self.minimumLineSpacing) * self.columnNumber;
    
    // 设置frame
    layoutArr.frame = CGRectMake(self.xForItemOrigin, self.yForItemOrigin, itemWidth, self.estimatedItemSize.height);
    // 放入数组
    [self.arrForItemAtrributes addObject:layoutArr];
}

@end

2、UICollectionViewCell子类
.h文件

#import <UIKit/UIKit.h>
#import "TextModel.h"

static CGFloat cellOrigin = 20;
static CGFloat cellWidth = 50;
static CGFloat cellHeight = 32;

@interface CollectionCell : UICollectionViewCell

@property (nonatomic, strong) TextModel *model;
//
@property (nonatomic, copy) void (^itemClick)(void);

/// cell动态宽
+ (CGFloat)widthCell:(NSString *)text;

@end

.m文件

#import "CollectionCell.h"

@interface CollectionCell ()

@property (nonatomic, strong) UIButton *button;

@end

@implementation CollectionCell

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = UIColor.clearColor;
        //
        [self setUI];
    }
    return self;
}

#pragma mark - 视图

- (void)setUI
{
    self.button = UIButtonInitializeWithTitle(self.contentView, CGRectZero, 0, nil, nil, kColorBlack, kColorBlue, kColorBlue, UIFontAutoSize(14), self, @selector(selectedButtonClick:));
    self.button.viewRadius(self.height / 2).viewBorder(1, kColorLineBorder);
    //
    [self.button mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.top.bottom.right.mas_equalTo(0);
    }];
}

- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes{
    
    UICollectionViewLayoutAttributes *attributes = [super preferredLayoutAttributesFittingAttributes:layoutAttributes];
    CGRect rect = self.button.frame;
    rect.size.width = self.model.nameWidth;
    rect.size.height =cellHeight;
    attributes.frame = rect;
    return attributes;
    
}

#pragma mark - 交互

- (void)selectedButtonClick:(UIButton *)button
{
    button.selected = YES;
    button.userInteractionEnabled = NO;
    self.button.viewBorder(1, kColorBlue);
    //
    self.model.selected = button.selected;
    if (self.itemClick) {
        self.itemClick();
    }
}

/// cell动态宽
+ (CGFloat)widthCell:(NSString *)text
{
    CGFloat width = [text widthForFont:UIFontAutoSize(14)];
    width += 20;
    width = (width <= 50 ? 50 : width);
    return width;
}

#pragma mark - setter/getter

- (void)setModel:(TextModel *)model
{
    _model = model;
    //
    CGFloat width = _model.nameWidth;
    if (width <= 0.0) {
        width = [[self class] widthCell:_model.name];
        model.nameWidth = width;
    }
    
    //
    NSString *text = _model.name;
    [self.button setTitle:text forState:UIControlStateNormal];

    if (_model.selected) {
        self.button.selected = YES;
        self.button.userInteractionEnabled = NO;
        self.button.viewBorder(kLineBorderWidth, kColorBlue);
    } else {
        self.button.selected = NO;
        self.button.userInteractionEnabled = YES;
        self.button.viewBorder(kLineBorderWidth, kColorLineBorder);
    }
    
    DLog(@"cell width = %.2f", width);
}

@end

3、UICollectionView子类
.h文件

#import <UIKit/UIKit.h>
#import "TextModel.h"
#import "CollectionCell.h"

NS_ASSUME_NONNULL_BEGIN

@interface Collection : UICollectionView

@property (nonatomic, strong) NSArray *array;
@property (nonatomic, copy) void (^cellClick)(NSIndexPath *indexPath);

@end

.m文件

#import "Collection.h"

@interface Collection () <UICollectionViewDelegate, UICollectionViewDataSource,UICollectionViewDelegateFlowLayout>

@property (nonatomic, strong) NSIndexPath *previousIndexPath;

@end

@implementation Collection

- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
    self = [super initWithFrame:frame collectionViewLayout:layout];
    if (self) {
        self.backgroundColor = UIColor.clearColor;
        //
        [self registerClass:CollectionCell.class forCellWithReuseIdentifier:@"CollectionCell"];
        self.delegate = self;
        self.dataSource = self;
    }
    return self;
}

#pragma mark - 交互

#pragma mark - UICollectionViewDelegate, UICollectionViewDataSource

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.array.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
   CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CollectionCell" forIndexPath:indexPath];
    
    TextModel *model = self.array[indexPath.row];
    cell.model = model;

    kSelfWeak;
    cell.itemClick = ^{
        if (weakSelf.previousIndexPath) {
            if ([weakSelf.previousIndexPath isEqual:indexPath]) {
                return ;
            }
            TextModel *previousModel = weakSelf.array[weakSelf.previousIndexPath.row];
            previousModel.selected = NO;
            [collectionView reloadItemsAtIndexPaths:@[weakSelf.previousIndexPath]];
        }
        weakSelf.previousIndexPath = indexPath;
        //
        if (weakSelf.cellClick) {
            weakSelf.cellClick(indexPath);
        }
    };

    return cell;
}

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
    return NO;
}

#pragma mark - setter

- (void)setArray:(NSArray *)array
{
    _array = array;
    //
    [_array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        TextModel *model = (TextModel *)obj;
        if (model.selected) {
            self.previousIndexPath = [NSIndexPath indexPathForRow:idx inSection:0];
            *stop = YES;
        }
    }];
    [self reloadData];
}

@end

4、实现

// 实例化
CollectionLayout *layout = [[CollectionLayout alloc] init];
layout.scrollDirection  = UICollectionViewScrollDirectionVertical;
layout.layoutWidth = self.width;
layout.delegate = self;
layout.autoContentSize = YES;
layout.minimumLineSpacing = cellOrigin / 2;
layout.minimumInteritemSpacing =cellOrigin / 2;
layout.sectionInset = UIEdgeInsetsMake(cellOrigin, cellOrigin, cellOrigin,cellOrigin);
layout.estimatedItemSize = CGSizeMake(cellWidth, cellHeight);

//
_collectionView = [[BCollection alloc] initWithFrame:CGRectMake(0, 0, self.width, (self.height / 2)) collectionViewLayout:layout];
[self addSubview:_collectionView];
_collectionView.backgroundColor = kColorWhite;
// 回调
kSelfWeak;
_collectionView.cellClick = ^(NSIndexPath * _Nonnull indexPath) {
            if (weakSelf.selecteClick) {
                weakSelf.selecteClick(indexPath);
            }
};
// 赋值
collectionView.array = _array;
// layout代理方法
- (CGFloat)widthForItemIndexPath:(NSIndexPath *)indexPath AndCollectioinView:(UICollectionView *)collectionView
{
    TextModel *model = self.array[indexPath.row];
    CGFloat width = model.nameWidth;
    if (width <= 0) {
        width = [CollectionCell widthCell:model.name];
        model.nameWidth = width;
    }
    return width;
}

编码注意事项

1、layout必须实现属性:layoutWidthminimumLineSpacingminimumInteritemSpacingsectionInsetestimatedItemSizedelegate。主要用于设置cell的大小,内边距和间距。
2、cell必须实现方法- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes,用于改变cell的大小。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

UICollectionViewCell自适应宽度 的相关文章

随机推荐

  • 第1课【寄存器开发到库开发】寄存器 库 位操作 封装 分层 GPIO

    目录 基本知识框架课堂笔记什么是寄存器开发什么是库开发寄存器开发和库开发的关联寄存器开发的基本流程寄存器开发的优缺点 库开发的基本流程库开发的优缺点 结论 如何从寄存器开发实现库开发 xff08 GPIO口为例 xff0c 通过操作其寄存器
  • python str基本用法

    目录 1 没什么用的 1 1 调用实例属性后自动执行 getattribute 1 2 实例化后自动调用 new 1 3 将其他变量转变为字符串 repr 1 4 反向替代占位符 格式化 rmod 1 5 字符串反向做乘法 rmul 1 6
  • 32.QButtonGroup

    目录 1 创建和添加按钮 1 1 创建按钮组 1 2 添加按钮 addButton 2 查看按钮 2 3 获取当前选中的按钮 CheckedButton 3 从按钮组中移除按钮 removeButton 4 ID操作 4 1 设置 setI
  • Windows下的Win32串口编程

    在工业控制中 xff0c 工控机 xff08 一般都基于Windows平台 xff09 经常需要与智能仪表通过串口进行通信 串口通信方便易行 xff0c 应用广泛 一般情况下 xff0c 工控机和各智能仪表通过RS485总线进行通信 RS4
  • Ubuntu内网穿透

    本文借鉴 使用frp进行内网穿透 少数派 目录 1 准备材料 2 服务端部署 3 服务端后台运行 4 客户端部署 1 准备材料 1 一台具有公网IP的实体机 xff08 服务端 xff0c 也可以是vps 2 一台网页部署内网的实体机 客户
  • Ubuntu系统基本操作

    文章中所需要的文件可以在这里下载 链接 xff1a https pan baidu com s 1NYXxHD0jebngmCTEwgjGbQ 提取码 xff1a 2jyo 目录 1 安装谷歌浏览器 2 修改开机启动项 3 快捷键查找与设置
  • Ubuntu向日葵锁定之后忘记密码后解除锁定状态

    此操作会重置本机识别码与本机验证码 我们在使用向日葵的时候会使用锁定按钮 设置完密码之后 xff0c 我们忘了 xff0c 就会导致无法使用向日葵 重新安装也不能解决问题 xff0c 这个时候我们找到etc orayconfig conf
  • 26.疲劳检测

    目录 1 项目介绍 2 代码实现 2 1 导入库 2 2 定义68个关键点 2 3 定义eye aspect ratio 2 4 定义参数 2 5 定义阈值 2 6 定义次数 2 7 创建检测器 2 8 获取左眼与右眼的起始点与终止点 2
  • NX点亮oled

    效果是这样的 目录 1 接线 2 配置环境 3 运行代码 4 显示开发板信息 1 接线 小屏幕的名称叫oled xff0c 使用芯片SSD1306驱动 上面有四个引脚 xff0c 与NX接线如下 VCC 5V GND GND SDA 3 S
  • 43.一维卷积-航空公司评论情感预测

    之前我们使用的都是二维卷积 xff0c 二维卷积处理图像问题 xff0c 这次我们使用一维卷积 xff0c 一维卷积处理序列问题 一维卷积就是在一个序列上进行滑动 xff0c 从而得出一维卷积的结果 xff0c 详细一维卷积的介绍可以看一下
  • serial库常见用法

    安装的时候要输入 pip install pyserial 进行安装 serial是python做串口通讯的库 xff0c 在这里介绍了NX与Windows串口通讯 NX串口通讯windows Suyuoa的博客 CSDN博客 目录 1 使
  • Ubuntu开机自启动一些东西

    有三种方式做开机自启动 目录 1 免除sudo密码 2 Startup 2 desktop 3 service 1 免除sudo密码 做完这一步你的所有sudo命令都不会再让你输密码了 如果你的开机自启动的东西需要sudo xff0c 那么
  • 附录3-动态组件 component与keep-alive setup()写法

    目录 1 基本使用 2 按钮切换组件 3 keep alive 3 1 在切换组件的时候 xff0c 默认情况下被切换的组件就会被销毁 3 1 1 数据情况 3 1 2 生命周期函数情况 3 2 使用 keep alive 3 3 keep
  • 附录11-插件ESLint与prettier

    ESLint是提示错误的 xff0c prettier是帮你解决错误的 目录 1 ESLint 1 1 安装 1 2 配置 1 3 效果 2 prettier 1 ESLint 1 1 安装 1 2 配置 在插件介绍中 xff0c 搜索 e
  • 用 C 语言编写 Windows 服务程序

    NTService cpp Defines the entry point for the console application include lt windows h gt include lt stdio h gt define S
  • 10.过滤器

    过滤器是做文本格式化的 xff0c 只能用在 插值表达式 与 v bind 上 xff0c 在vue3中已经被弃用了 xff0c 这里我简单记录一下并写一下在vue3的替代方法 目录 1 基本使用 1 1 vue2中的写法 1 2 vue3
  • 24.eslint

    eslint是约束代码写法的插件 xff0c 比如组件的命名必须要用驼峰命名这种 eslint官网 检测并修复 JavaScript 代码中的问题 ESLint 插件化的 JavaScript 代码检查工具 目录 1 vue cli的esl
  • CocoaPods的使用——pod install pod install --repo-update pod update pod update --repo-update

    Podfile文件中 xff0c 使用某个库时 不指定版本 xff0c 表示希望使用最新版本 xff0c 如 pod SDWebImage 指定明确版本 xff0c 表示只想要这个版本 xff0c 如 xff1a pod 39 SDWebI
  • SceneDelegate有什么作用?删除有什么影响

    自从Xcode11发布以来 xff0c 当你使用新XCode创建一个新的iOS项目时 xff0c SceneDelegate会被默认创建 xff0c 它到底有什么用呢 xff1f 在iOS 13 xff08 及以后版本 xff09 上 xf
  • UICollectionViewCell自适应宽度

    如图所示效果 xff0c 根据字符长度自适应UICollectionViewCell的大小 xff0c 同时进行左对齐处理 如何实现 继承UICollectionViewFlowLayout创建子类 xff0c 并实现相关的方法 xff0c