Cell的高度自适应

序言:

本文主要讲在iOS开发过程中,TableView这个控件是每个开发者几乎都会使用到的控件,应该说是必不可少的控件,而往往的需求就是需要Cell的高度做一个动态适应,因为Cell中的内容可能是不定的,当然通过Model拿到数据之后,去手动计算Frame以及相关约束是没问题的,但是开发效率会相对于采用AutoLayout的自适应高度以及相关约束就显得低下了;本例主要是希望能帮助一些开发者在处理Cell布局以及高度时因频繁的拿到Model之后去计算或者更新相关Frame而感到厌恶的一种帮助吧.

Tastes all differ.

废话不多说,进入正题

UITableView自适应高度布局

实现效果大致如下:

说明:

  1. 本例中Cell的高度不是通过手动计算的.
  2. 本例中用红色框圈起来的部分是一个要注意的地方,就是姓名要求全部展示,职位和公司那块,职位要求优先全部展示,公司名可以不全部展示.代码中关于这块部门有注释,可以注意下.
  3. 本例中使用的布局约束是:Masonry + FDTemplateLayoutCell;FDTemplateLayoutCell是一个在Git上开源的一个关于TableView高度相关的一个比较好用的第三方,当然Star的数量也是很多的,毕竟作者是Sunny,其地址是:FDTemplateLayoutCell

  4. 在使用时,如果是与Masorny 结合使用的或者用的xib原理与效果是一样的,只是在约束时不能少约束了,不然无法准确的得到Cell的高度;有个要注意的点,就是在约束子控件时,最上面的控件相对于父视图的top属性别忘记,以及最底下的控件相对于父视图的bottom属性也别忘记,否则是无法正确计算出Cell高度的.

  5. TableView在初始化的时候,

    tableView.estimatedRowHeight = 120.0;
    tableView.rowHeight = UITableViewAutomaticDimension;
    

    这两个属性记得要带上,否则可能会出现想不到的效果.

实现过程

1. 自定义Cell,这一步肯定是比不可少的.

.h文件代码如下

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

    @class ITAtutoCellHeightModel;

    @interface ITAutoHeightCell : UITableViewCell

    @property (nonatomic,weak) id   <ZJAutoHeightCellDelegate> delegate;

    - (void)setModel:(ITAtutoCellHeightModel *)model;

    @end

.m文件代码如下

    #import "ITAutoHeightCell.h"
    #import "ITAtutoCellHeightModel.h"
    #import <YYKit/YYKit.h>

    #import <Masonry/Masonry.h>

    #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

2. 在TableView中使用对应的Cell

  1. 注册相应的Cell
  2. - (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]];
    }

  3. 注意HeightForCell该方法中的相关改变:

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return [tableView fd_heightForCellWithIdentifier:kIdentifier cacheByIndexPath:indexPath configuration:^(ITAutoHeightCell *cell) {
        [self configureCell:cell atIndexPath:indexPath];
    }];
    }
    

总结

  1. 使用Masonry(或者Xib) 约束好Cell中的子控件.
  2. 向Table中注册cell
  3. 根据ID找到对应的cell,根据Cell中子控件的约束,自动计算出Cell的高度
  4. Model赋值

个人觉着这种方式是很方便的,而且该第三方中分为使用缓存和不使用缓存的API,在使用的过程中可以自己去体验下有缓存和无缓存的区别;希望能对不想手动计算Cell高度的开发者有帮助.有问题可以在下方提问,我会尽力去解答;如果有需要Demo的同学,可以在下方留言.

备注:转载请注明,请尊重原创者的劳动成果,谢谢配合.
如果有不明白或者有什么建议,欢迎在评论下方留言,我会尽力在第一时间回复的.欢迎大家来共同讨论学习.
### iOS 张袁旭

猜你喜欢

转载自blog.csdn.net/freshmancode/article/details/80282330