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自适应宽度 的相关文章

随机推荐

  • 【Android控件】HorizontalScrollView的基础使用记录(滚动条自定义)

    目录 效果图 简介 注意事项 基础属性 滚动条全部设置 滚动条是否总显示 自定义滚动条滑动背景和滚动条背景 设置滚动条的宽度 设置滚动条距离 其它常规设置 设置滚动速度 布局代码示例 总结 效果图 简介 HorizontalScrollVi
  • C语言知识点笔记

    C语言知识点笔记 文章目录 C语言知识点笔记前言1 那些语句不用 结尾2 uint32 uint16等整形数据类型属于stdint h头文件3 int p1 char p2 之间的区别4 相同类型指针相加减5 如何将int p 指定指定地址
  • 【魔兽世界】WLK版本的常规宏教程

    文章目录 宏 常规指令和语法 基础指令 队列施法 攻击 动作条 取消 目标选择 模拟点击 图标及提示 判断条件 在不失去当前目标的情况下 xff0c 定位另一目标 语法 注意事项 宏例子 上马跟随宏 神牧攻击宏 牧师驱散宏 我的常用指令及判
  • 【Flutter·学习实践·UI篇】基础且重要的UI知识

    前言 参考学习官网 xff1a Flutter实战 第二版 学习前先记住 xff1a Flutter 中万物皆为Widget xff0c 心中默念3次以上铭记于心 这一点和开发语言Dart的变量一切皆是对象的概念 xff0c 相互对应 Wi
  • 【lua初级篇】基础知识和开发工具

    文章介绍 文章介绍 简述 工具安装配置和下载 快速看基础知识 一些常用的关键字一览 数据类型 table xff1a 运算符 算术运算符 关系运算符 逻辑运算符 条件语句的形式 注释 单行注释 多行注释 总结 xff1a 简述 没时间玩魔兽
  • 【Flutter·学习实践·配置】认识配置文件pubspec.yaml

    目录 简介 pubspec yaml 添加Pub仓库 其他依赖方式 依赖本地包 依赖Git 简介 简单说就是包管理工具 xff0c 类似于Android 提供了 Gradle 来管理依赖 xff0c iOS 用 Cocoapods 或 Ca
  • Ubuntu快速重装教程!拯救你的系统!

    目录 1 删除旧分区 1 1删除除EFI分区外的Ubuntu分区 1 2删除EFI分区 2 安装Ubuntu 首先抱抱点进这个标题的小伙伴 xff0c 你们一定是饱受现在系统的折磨才选择重装的 xff08 答主也经历过 xff0c 项目竞标
  • JVM性能调优篇07-阿里巴巴Arthas工具详解

    Arthas工具 Arthas 是 Alibaba 在 2018 年 9 月开源的 Java 诊断工具 支持 JDK6 43 xff0c 采用命令行交互模式 xff0c 可以方便的定位和诊断线上程序运行问题 Arthas 官方文档十分详细
  • ThinkPHP 鲜为人知的 selectAdd 方法 addAll( select() )

    TP算是国内相当热门的一个PHP框架 xff0c 相信大家对TP的普通增删查改所用的select add save delect find getField 等等内置函数早已烂熟于心了 今天 xff0c 就向大家介绍一种TP手册中未提及 x
  • 算法多线程leetcode题目总结(多解法实现)

    简介 本文汇总了leetcode上多线程题目 xff0c 并对每一道题进行多方法解答 xff0c 并分析不同方法之间的优劣 文中示例代码为Java 题目 1114 按序打印 简单1115 交替打印FooBar 中等1116 打印零与奇偶数
  • java.lang.IllegalStateException Unable to find a @SpringBootConfiguration错误解决方案

    java lang IllegalStateException Unable to find a 64 SpringBootConfiguration you need to use 64 ContextConfiguration or 6
  • 智慧型物业管理系统功能解析

    随着当前社会经济的发展与科技发达 xff0c 物业管理系统化已经成为常态了 尤其是随着智慧物业管理系统功能越来越多 xff0c 人们对智慧物业管理系统的依赖就更明显了 毕竟系统真的可以给生活带来很多的便利之处 xff1a 业主可通过该系统查
  • spring依赖注入

    目录 1 使用bean标签注入 1 pom xml文件配置 2 spring配置文件 xff08 存放bean spring注解等相关信息的文件 xff09 3 bean标签生成对象 4 对象的依赖注入 1 通过set方法 xff1a xf
  • 【Python爬虫】百度百科词条内容

    词条内容 我这里随便选取了一个链接 xff0c 用的是FBI的词条 import urllib request import urllib parse from lxml import etree def query url headers
  • redis特性

    Redis特性 1 速度快 正常情况下Redis执行命令的速度是非常快的 xff0c 官方给出的数字是读写性能可以达到10万 秒 xff0c 当然这个也取决于机器的性能 xff0c 这里暂且不考虑 到底什么早就了Redis的速度如此之快呢
  • Linux twm

    在linux安装GO 修改了环境变量 GO PATH 61 opt go go JAVA HOME 61 usr java jdk1 6 0 31 PATH 61 JAVA HOME bin GO PATH bin color 61 red
  • 【七夕节】浪漫七夕,代码传情。将爱意变成绚烂的立体场景,给她(他)一个惊喜!(送代码)

    浪漫七夕 xff0c 代码传情 将爱意变成绚烂的立体场景 xff0c 给她 xff08 他 xff09 一个惊喜 xff01 一 python代码 xff08 情话转二进制编码 xff09 二 js代码部分 xff08 二进制编码生成立体场
  • 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