—开篇:在我们开发中经常会用到UITableView, TableView上面的cell有时候非常复杂,高度可变、结构可变等等。那么这个时候我们该如何去自适应cell的高度呢。
一.通过frame去计算
第一种大家比较容易想到的方法,就是由上往下依次计算控件的frame,再将最下面的控件frame的最大y值拿到,赋值给整个cell_height,得到整个cell的最终高度。
简单布局的就可直接计算,但,如果复杂一些,结构多变,就需要另外创建一个frameModel来专门计算和存储cell的frame。这种情况逻辑复杂,也比较容易出错。
######需要创建两个模型:model(存储数据)、frameModel(存储cell上子view的frame)
两者间的关系:frameModel是通过model来进行设置的,通过传入的model中的属性,来判断cell中子view显示或隐藏,从而一步一步得到所有的子view的frame值,最后,将cell的高度保存起来。
1 | // model.h |
1 | // FrameModel.h |
1 | // FrameModel.m |
1 | // cell.h |
1 | // cell.m |
这一步步走下来应该非常直观的。
最后也就只有一步了,将拿到的数据进行model和frameModel之间的转换。
1 | /** |
接下来就是数据展示咯,将frameModel导入进cell里面就OK了。
这其实是一种分离思路,将各个模块分离化,逻辑会清晰很多,对于复杂的数据和UI异常适合。
额,其中有一个sizeWithFont,是我创建的一个分类,只是为了简化代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// NSString+Extension.m
- (CGSize)sizeWithFont:(UIFont *)font maxW:(CGFloat)maxW {
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSFontAttributeName] = font;
CGSize maxSize = CGSizeMake(maxW, MAXFLOAT);
NSString *version = [UIDevice currentDevice].systemVersion;
if ([version doubleValue] > 7.0) {
return [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size;
}else {
return [self sizeWithFont:font constrainedToSize:maxSize];
}
}
- (CGSize)sizeWithFont:(UIFont *)font {
return [self sizeWithFont:font maxW:MAXFLOAT];
}
二.通过自动布局自动适配(推荐使用)
1.在cell中,setModel方法中所做的事情只是将数据导入view中进行展示,其他都不用管。label的话需要设定preferredMaxLayoutWidth属性。1
2
3
4
5
6
7
8
9
10
11
12
13// cell.m
- (void)setModel:(Model *)model {
_model = model;
// 头像
[self.iconView sd_setImageWithURL:[NSURL URLWithString:model.icon]];
// 昵称
self.nameLabel.text = model.name;
CGFloat screen_Width = [UIScreen mainScreen].bounds.size.width;
CGFloat width = screen_Width - 35 - 5; // label的宽度
// 自动布局:设定label文字的最大宽度,这个宽度也可以通过外部进行传递,从而设定。
self.nameLabel.preferredMaxLayoutWidth = width;
}
2.在获取cellHeight代理方法中,因为可能无法获取到当前的cell,我们的目的只是要得到cell的高度,所以在这我们创建了一个临时变量cell,用来计算cellHeight。1
2
3
4
5
6
7- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
self.cell.nameLabel.text = nil;
self.cell.model = self.models[indexPath.row];
// cell进行自动布局,可以得到cellHeight
CGFloat cellHeight = [self.cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height+1;
return cellHeight>31.0f? cellHeight:31.0f;
}
后记:如果有些需求是想得到tableview最大的高度,让cell完全展示出来,可以监听tableView的contentSize属性。
注:iOS10以下,监听contentSize属性;iOS10及以上监听scrollView.contentSize属性。1
2
3
4
5
6float iOS_version = [[[UIDevice currentDevice] systemVersion] floatValue];
if (iOS_version >= 8.0 && iOS_version < 10.0) {
[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}else if (iOS_version >= 10.0) {
[self.tableView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
}
1 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { |
看到这里,或许你挥一挥衣袖,只留下了一个赞。😄