本文主要讲在iOS开发过程中,TableView这个控件是每个开发者几乎都会使用到的控件,应该说是必不可少的控件,而往往的需求就是需要Cell的高度做一个动态适应,因为Cell中的内容可能是不定的,当然通过Model拿到数据之后,去手动计算Frame以及相关约束是没问题的,但是开发效率会相对于采用AutoLayout的自适应高度以及相关约束就显得低下了;本例主要是希望能帮助一些开发者在处理Cell布局以及高度时因频繁的拿到Model之后去计算或者更新相关Frame而感到厌恶的一种帮助吧.
Tastes all differ.
废话不多说,进入正题
本例中Cell的高度不是通过手动计算的.
本例中用红色框圈起来的部分是一个要注意的地方,就是姓名要求全部展示,职位和公司那块,职位要求优先全部展示,公司名可以不全部展示.代码中关于这块部门有注释,可以注意下.
本例中使用的布局约束是:Masonry + FDTemplateLayoutCell;FDTemplateLayoutCell是一个在Git上开源的一个关于TableView高度相关的一个比较好用的第三方,当然Star的数量也是很多的,毕竟作者是Sunny,其地址是:FDTemplateLayoutCell
在使用时,如果是与Masorny 结合使用的或者用的xib原理与效果是一样的,只是在约束时不能少约束了,不然无法准确的得到Cell的高度;有个要注意的点,就是在约束子控件时,最上面的控件相对于父视图的top属性别忘记,以及最底下的控件相对于父视图的bottom属性也别忘记,否则是无法正确计算出Cell高度的.
TableView在初始化的时候,
tableView.estimatedRowHeight = 120.0;
tableView.rowHeight = UITableViewAutomaticDimension;
这两个属性记得要带上,否则可能会出现想不到的效果.
.h文件代码如下
#import
#import "ZJAutoHeightCellDelegate.h"
@class ITAtutoCellHeightModel;
@interface ITAutoHeightCell : UITableViewCell
@property (nonatomic,weak) id delegate;
- (void)setModel:(ITAtutoCellHeightModel *)model;
@end
.m文件代码如下
#import "ITAutoHeightCell.h"
#import "ITAtutoCellHeightModel.h"
#import
#import
#define RGB(r, g, b) RGBA(r, g, b, 1.0f)
#define Font(a) [UIFont systemFontOfSize:a]
@interface ITAutoHeightCell()
@property (nonatomic, strong) UILabel *nameLab;
@property (nonatomic, strong) UILabel *positionLab;
@property (nonatomic, strong) UILabel *companyLab;
@property (nonatomic, strong) UILabel *ageLab;
@property (nonatomic, strong) UILabel *sexLab;
@property (nonatomic, strong) UIImageView *avatar;
@property (nonatomic, strong) UILabel *describeLab;
@property (nonatomic, strong) UIView *sepratorLine;
@end
@implementation ITAutoHeightCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
self.selectionStyle = UITableViewCellSelectionStyleNone;
[self loadSubViews];
[self addConstraints];
}
return self;
}
// MARK: - 添加子控件
- (void)loadSubViews {
__weak typeof(self) weakSelf = self;
_avatar = [[UIImageView alloc]init];
_avatar.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithActionBlock:^(id sender) {
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(didClickUserAvatar)]) {
[weakSelf.delegate didClickUserAvatar];
}
}];
[_avatar addGestureRecognizer:tapGesture];
[self.contentView addSubview:_avatar];
_nameLab = [UILabel new];
_nameLab.font = Font(15.0f);
_nameLab.textColor = [UIColor blackColor];
_nameLab.backgroundColor = [UIColor redColor];
[self.contentView addSubview:_nameLab];
//尽量完整显示
// MARK: - position 尽量完整显示
_positionLab = [UILabel new];
_positionLab.font = Font(13.0);
_positionLab.userInteractionEnabled = YES;
_positionLab.backgroundColor = [UIColor greenColor];
_positionLab.textColor = [UIColor lightGrayColor];
//不可以被压缩,尽量显示完整
[_positionLab setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
UITapGestureRecognizer *tapPosition = [[UITapGestureRecognizer alloc]initWithActionBlock:^(id sender) {
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(didClickUserPosition)]) {
[weakSelf.delegate didClickUserPosition];
}
}];
[_positionLab addGestureRecognizer:tapPosition];
[self.contentView addSubview:_positionLab];
//可以被压缩显示
// MARK: - 公司名可以压缩显示
_companyLab = [UILabel new];
_companyLab.font = Font(13.0);
_companyLab.backgroundColor = [UIColor yellowColor];
_companyLab.userInteractionEnabled = YES;
//宽度不够时,可以被压缩
[_companyLab setContentCompressionResistancePriority:UILayoutPriorityFittingSizeLevel forAxis:UILayoutConstraintAxisHorizontal];
//抱紧,压缩
[_companyLab setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
_companyLab.textColor = [UIColor blueColor];
UITapGestureRecognizer *tapCompany = [[UITapGestureRecognizer alloc]initWithActionBlock:^(id sender) {
if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(didClickUserCompany:)]) {
[weakSelf.delegate didClickUserCompany:self];
}
}];
[_companyLab addGestureRecognizer:tapCompany];
[self.contentView addSubview:_companyLab];
_ageLab = [UILabel new];
_ageLab.font = Font(13.0f);
_ageLab.textColor = [UIColor lightGrayColor];
[self.contentView addSubview:_ageLab];
_sexLab = [UILabel new];
_sexLab.font = Font(12.0f);
_sexLab.textColor = [UIColor lightGrayColor];
[self.contentView addSubview:_sexLab];
_describeLab = [UILabel new];
_describeLab.font = Font(14.0f);
_describeLab.numberOfLines = 0;
_describeLab.lineBreakMode = NSLineBreakByCharWrapping;
_describeLab.backgroundColor = [UIColor yellowColor];
[self.contentView addSubview:_describeLab];
_sepratorLine = [UIView new];
[_sepratorLine setHidden:YES];
_sepratorLine.backgroundColor = [UIColor lightGrayColor];
[self.contentView addSubview:_sepratorLine];
}
// MARK: - 添加约束
- (void)addConstraints {
[self.avatar mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.contentView).offset(15);
make.width.height.equalTo(@(70));
}];
//namelabel 后面如果还跟着有label,要做自适应宽度,namelabl的宽度不能写死,自适应宽度
[self.nameLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.avatar.mas_right).offset(15);
make.top.equalTo(self.avatar).offset(4);
}];
[self.positionLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.nameLab.mas_right).offset(10);
make.top.equalTo(self.nameLab.mas_top).offset(1);
}];
[self.companyLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.positionLab.mas_right).offset(10);
make.top.equalTo(self.nameLab.mas_top).offset(0);
//priorityLow 如果不加优先级,会出现三个label都能显示的情况下,namelabel会偏差很多
make.right.equalTo(self.contentView).offset(-10).priorityLow();
}];
[self.ageLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.nameLab).offset(0);
make.top.equalTo(self.nameLab.mas_bottom).offset(8);
make.right.equalTo(self.contentView).offset(-15);
}];
[self.sexLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.nameLab).offset(0);
make.top.equalTo(self.ageLab.mas_bottom).offset(8);
make.right.equalTo(self.contentView).offset(-15);
}];
[_describeLab mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(15);
make.top.equalTo(self.avatar.mas_bottom).offset(15);
make.right.bottom.equalTo(self.contentView).offset(-15);
}];
[_sepratorLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.contentView).offset(15);
make.right.equalTo(self.contentView).offset(-15);
make.height.equalTo(@0.5);
make.bottom.equalTo(@(0));
}];
}
// MARK: - 赋值
- (void)setModel:(ITAtutoCellHeightModel *)model {
[_avatar sd_setImageWithURL:[NSURL URLWithString:model.avatar] placeholderImage:[UIImage imageNamed:@"to"]];
[_nameLab setText:model.name];
if ([model.isHightLight isEqualToString:@"1"]) {
[self.contentView setBackgroundColor:RGB(187, 242, 204)];
} else {
[self.contentView setBackgroundColor:[UIColor whiteColor]];
}
[_positionLab setText:model.position];
[_companyLab setText:model.company];
[_ageLab setText:model.age];
[_sexLab setText:model.sex];
[_describeLab setText:model.describe];
}
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
@end
注册相应的Cell
在 **- (UITableViewCell *)tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath )indexPath 中
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ITAutoHeightCell *cell = [tableView dequeueReusableCellWithIdentifier:kIdentifier forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
//配置Cell中对应的Model
- (void)configureCell:(ITAutoHeightCell *)cell atIndexPath:(NSIndexPath *)indexPath{
[cell setModel:[_viewModel cellModel:indexPath]];
}
注意HeightForCell该方法中的相关改变:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return [tableView fd_heightForCellWithIdentifier:kIdentifier cacheByIndexPath:indexPath configuration:^(ITAutoHeightCell *cell) {
[self configureCell:cell atIndexPath:indexPath];
}];
}
个人觉着这种方式是很方便的,而且该第三方中分为使用缓存和不使用缓存的API,在使用的过程中可以自己去体验下有缓存和无缓存的区别;希望能对不想手动计算Cell高度的开发者有帮助.有问题可以在下方提问,我会尽力去解答;如果有需要Demo的同学,可以在下方留言.
备注:转载请注明,请尊重原创者的劳动成果,谢谢配合.
如果有不明白或者有什么建议,欢迎在评论下方留言,我会尽力在第一时间回复的.欢迎大家来共同讨论学习.
### iOS 张袁旭