UICollectionViewCell自适应宽度

UICollectionViewCell自适应宽度_第1张图片

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

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

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

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

#import 

NS_ASSUME_NONNULL_BEGIN

@protocol CollectionLayoutDelegate 

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

@end

@interface CollectionLayout : UICollectionViewFlowLayout

@property (nonatomic, weak) iddelegate;
/// 视图宽
@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 
#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 
#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 () 

@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的大小。

你可能感兴趣的:(iOS)