需求背景
1、UITableViewCell 嵌套 UICollectionView
2、UICollectionViewCell 宽度根据文字长度变化(宽度不固定)
3、UITableViewCell 根据 UICollectionView 内容实现高度自适应(UICollectionView 不可滚动)
需求痛点
UICollectionViewCell 宽度根据文字自适应,因此无法确定一行能容纳几个 UICollectionViewCell
效果实现
初始化 UICollectionView
UICollectionViewFlowLayout * layout = [[UICollectionViewFlowLayout alloc] init];
// 1、使用 Autolayout 一定要给 Item 预估个宽高,否则无法自适应宽度
// 2、Item 宽度不能超出实际 UICollectionView 宽度,否则 UICollectionView 高度计算异常
layout.estimatedItemSize = CGSizeMake(100, 22);
UICollectionView * coll = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
coll.backgroundColor = [UIColor whiteColor];
coll.delegate = self;
coll.dataSource = self;
[coll registerClass:[CustomTableViewCollCell class] forCellWithReuseIdentifier:[CustomTableViewCollCell identifier]];
// 调用私有方法设置居左,否则当只有一个 item 的时候会居中显示,调用该方法不影响审核
SEL sel = NSSelectorFromString(@"_setRowAlignmentsOptions:");
if ([coll.collectionViewLayout respondsToSelector:sel]) {
((void(*)(id, SEL, NSDictionary*)) objc_msgSend)(coll.collectionViewLayout, sel, @{@"UIFlowLayoutCommonRowHorizontalAlignmentKey": @(NSTextAlignmentLeft), @"UIFlowLayoutLastRowHorizontalAlignmentKey": @(NSTextAlignmentLeft), @"UIFlowLayoutRowVerticalAlignmentKey": @(NSTextAlignmentLeft)});
}
[self.contentView addSubview:coll];
_coll = coll;
// 这里不设置 UICollectionView 高度
[coll mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(abnormalTitleLabel.mas_right).offset(20);
make.right.equalTo(self.contentView).offset(-15);
make.top.equalTo(abnormalTitleLabel.mas_top);
make.bottom.equalTo(self.contentView).offset(-20);
}];
在 UICollectionViewCell 重写 preferredLayoutAttributesFittingAttributes: 方法
- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
// 这两个不能少
[self setNeedsLayout];
[self layoutIfNeeded];
UICollectionViewLayoutAttributes * attributes = [super preferredLayoutAttributesFittingAttributes:layoutAttributes];
// 在这里计算文字的宽度
CGSize size = [@"我是用来计算文字宽度的" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 17) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:12]} context:nil].size;
CGRect cellFrame = attributes.frame;
// size.width 只是文字的宽度,要加上其他组件的宽和间距,这样才得到正确的 UICollectionViewCell 宽度
cellFrame.size.width = size.width + 30;
attributes.frame = cellFrame;
return attributes;
}
不要重写 collectionView:layout:sizeForItemAtIndexPath: 方法
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
// 不要重写这个方法
}
在 UITableViewCell 重写 systemLayoutSizeFittingSize:withHorizontalFittingPriority:horizontalFittingPriority: 方法 iOS8及之后版本可用
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority {
CGSize size = [super systemLayoutSizeFittingSize:targetSize withHorizontalFittingPriority:horizontalFittingPriority verticalFittingPriority:verticalFittingPriority];
// 这个不能少,否则 self.coll.collectionViewLayout.collectionViewContentSize.height = 0
[self.coll layoutIfNeeded];
// 这里得到 UICollectionView 内容的宽高
CGSize collSize = self.coll.collectionViewLayout.collectionViewContentSize;
return CGSizeMake(size.width, size.height+collSize.height);
}
注意
使用 Autolayout 布局 UITableViewCell 并实现动态高度时,一定要确保约束能够撑开 UITableViewCell 否则将会得到错误的高度44。
文章有(1)条网友点评
写的很棒 但是感觉代码写出来不太优雅 我感觉UICollectionView不太适合自适应 还是用Frame比较好