iOS8 新特性Self-Sizing Cells,自动计算cell的高度
一、简单介绍
UITableView是iOS开发最常用的一个控件,通过代理和数据源方法,几乎能实现各种各样的列表功能。在这里面,有一个比较重要的属性是行高rowHeight,默认的行高是44px。很显然,默认的高度有时候很难满足这个功能的需求:"cell的高度动态改变"。最常见的就是朋友圈,微博,评论列表类的cell,因为用户评论的内容长度不同,导致cell的高度也不同。
二、旧的解决
那么,以前我们是如何计算cell的高度?我的做法是给每一个模型定义一个cellHeight属性,通过模型提前来计算 (此方法一般为了适配iOS7用),然后在tableView:heightForRowAtIndexPath中拿出模型的这个属性返回即可。这种做法虽然可以,但是毕竟会多写一些代码。针对如此,苹果帮我们在iOS8做了优化。
三、新的出世
Self-Sizing Cells,iOS8新出现的特性,可以自动实现cell高度的计算。我们只需要做三件事:
1、给tableView设置预估高度estimatedRowHeight,提高tableView的滚动性能;
2、给tableView的rowHeight设置自动尺寸UITableViewAutomaticDimension;
3、给cell.contentView中的子控件添加Auto Layout相对约束(top、bottom上下约束必须完整,因为需要自动计算高度),推荐使用mansory约束。
四、两者区别
通过计算去设置cell的行高,除了会添加了多余的多码,影响效率,另外添加性的控件需要重新计算,不利用扩展。
通过Self-Sizing Cells新特性可以省去可不必要的代码,新添加控件只需要调整约束,扩展起来很方便。
五、使用案例
TableViewController
// // ViewController.m // cell自动计算行高 // // Created by 夏远全 on 2017/9/30. // Copyright © 2017年 夏远全. All rights reserved. // #import "TableViewController.h" #import "TableViewCell.h" @interface TableViewController () @property (strong , nonatomic)NSMutableArray *dataSource; @end @implementation TableViewController - (void)viewDidLoad { [super viewDidLoad]; //预估行高 self.tableView.estimatedRowHeight = 100; //自动尺寸 self.tableView.rowHeight = UITableViewAutomaticDimension; //去除空白 self.tableView.tableFooterView = [[UIView alloc] init]; } -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ return self.dataSource.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *reuserIdentifier = @"TableViewCell"; TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuserIdentifier]; if (!cell) { cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuserIdentifier]; } cell.modelDic = self.dataSource[indexPath.row]; return cell; } -(NSMutableArray *)dataSource{ if (!_dataSource) { _dataSource = [NSMutableArray array]; [_dataSource addObject:@{@"avatar":@"image1.png",@"name":@"美女与野兽",@"instruction":@"遥映人间冰雪样,暗香幽浮曲临江。 遍识天下英雄路,俯首江左有梅郎"}]; [_dataSource addObject:@{@"avatar":@"image2.png",@"name":@"哪有几回闻",@"instruction":@"iOS基于RTMP的视频推流 一、基本介绍 iOS直播一出世,立马火热的不行,各种直播平台如雨后春笋,正因为如此,也同样带动了直播的技术快速发展,在IT界精通直播技术的猴子可是很值钱的。"}]; [_dataSource addObject:@{@"avatar":@"image3.png",@"name":@"绝天地苍穹",@"instruction":@"**政治局第四十三次集体学习时强调 深刻认识马克思主义时代意义和现实意义 继续推进马克思主义中国化时代化大众化"}]; } return _dataSource; } @end
TableViewCell
// // TableViewCell.h // cell自动计算行高 // // Created by 夏远全 on 2017/9/30. // Copyright © 2017年 夏远全. All rights reserved. // #import <UIKit/UIKit.h> @interface TableViewCell : UITableViewCell @property (strong , nonatomic)NSDictionary *modelDic; @end
// // TableViewCell.m // cell自动计算行高 // // Created by 夏远全 on 2017/9/30. // Copyright © 2017年 夏远全. All rights reserved. // #import "TableViewCell.h" #import <Masonry.h> @interface TableViewCell () @property (strong,nonatomic)UIImageView *avatarView; @property (strong,nonatomic)UILabel *nameLabel; @property (strong,nonatomic)UILabel *instrLabel; @end @implementation TableViewCell #pragma mark - life cycle -(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setup]; } return self; } -(instancetype)init { if (self = [super init]) { [self setup]; } return self; } -(instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { [self setup]; } return self; } -(void)setup { [self setupSubViews]; [self setupSubviewsConstraints]; } #pragma mark - add subViews -(void)setupSubViews{ [self.contentView addSubview:self.avatarView]; [self.contentView addSubview:self.nameLabel]; [self.contentView addSubview:self.instrLabel]; } #pragma mark - layout subviews -(void)setupSubviewsConstraints { [self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.contentView.mas_left).offset(20); make.top.mas_equalTo(self.contentView.mas_top).offset(20); make.size.mas_equalTo(CGSizeMake(44, 44)); }]; [self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.avatarView.mas_right).offset(20); make.right.mas_equalTo(self.contentView.mas_right).offset(-20); make.top.mas_equalTo(self.contentView.mas_top).offset(20); }]; [self.instrLabel mas_makeConstraints:^(MASConstraintMaker *make) { make.left.mas_equalTo(self.avatarView.mas_right).offset(20); make.right.mas_equalTo(self.contentView.mas_right).offset(-20); make.top.mas_equalTo(self.nameLabel.mas_bottom).offset(10); make.bottom.mas_equalTo(self.contentView.mas_bottom).offset(-20);//此处cell的高度就被算出来了 }]; } #pragma mark - event response #pragma mark - public methods #pragma mark - private methods #pragma mark - getters and setters -(void)setModelDic:(NSDictionary *)modelDic{ _modelDic = modelDic; self.avatarView.image = [UIImage imageNamed:modelDic[@"avatar"]]; self.nameLabel.text = modelDic[@"name"]; self.instrLabel.text = modelDic[@"instruction"]; } -(UIImageView *)avatarView{ if (!_avatarView) { _avatarView = [[UIImageView alloc] init]; } return _avatarView; } -(UILabel *)nameLabel{ if (!_nameLabel) { _nameLabel = [[UILabel alloc] init]; _nameLabel.numberOfLines = 0; } return _nameLabel; } -(UILabel *)instrLabel{ if (!_instrLabel) { _instrLabel = [[UILabel alloc] init]; _instrLabel.numberOfLines = 0; } return _instrLabel; } @end
六、演示效果