关于UItableViewCell中使用AutoLayout的解决方案网上有一堆介绍文章,我之前也写过一篇UITableView自适应cell高度,问题解决的思路就是使用estimatedRowHeight
来估算行高,但这样有一个问题就是 如果估算高度与实际高度相差较大,那么页面的来回蹦跳会让你怀疑人生。
为了解决这个问题,在我的项目中是这样来计算Cell高度的。
解决问题思路
1、依然使用autolayout填充cell,保证cell的contentView上下被子视图撑开。
2、使用systemLayoutSizeFittingSize自动计算cell大小。
那么怎么来自动计算cell的高度呢?
假设我们有一个自定义的类AutoLayoutCell
,他继承自UITableViewCell
。
AutoLayoutCell.h
#import <UIKit/UIKit.h>
@interface AutoLayoutCell : UITableViewCell
+ (CGFloat)heightWithString:(NSString *)str;
- (void)setCellString:(NSString *)str;
@end
AutoLayoutCell.m
#import "AutoLayoutCell.h"
#import <Masonry/Masonry.h>
@interface AutoLayoutCell ()
@property (strong, nonatomic) UILabel *contentLabel;
@end
@implementation AutoLayoutCell
+ (CGFloat)heightWithString:(NSString *)str
{
//单例的离屏cell
static AutoLayoutCell *offscreenCell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
offscreenCell = [[AutoLayoutCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Identifier"];
});
//向cell中填充数据
[offscreenCell setCellString:str];
//更新约束,防止在填充数据时更新了约束条件
[offscreenCell setNeedsUpdateConstraints];
[offscreenCell updateConstraintsIfNeeded];
//设置屏幕的bounds,注意这里的cellWidth并非一定是屏幕宽度,需要结合实际情况
CGFloat cellWidth = [UIScreen mainScreen].bounds.size.width;
offscreenCell.bounds = CGRectMake(0, 0, cellWidth, CGRectGetHeight(offscreenCell.bounds));
[offscreenCell setNeedsLayout];
[offscreenCell layoutIfNeeded];
//自动计算layout的size
CGSize size = [offscreenCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
CGFloat height = size.height;
//如果有分割线,需要加上分割线高度
return height+1;
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//自动填充布局
[self.contentView addSubview:self.contentLabel];
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 16, 10, 16));
}];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
//如果有label,要设置label的preferredMaxLayoutWidth
//注意这里使用的是layoutIfNeeded,而不是layoutSubviews
[self.contentView layoutIfNeeded];
self.contentLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.contentLabel.bounds);
}
- (void)setCellString:(NSString *)str
{
self.contentLabel.text = str;
}
#pragma mark - getter
- (UILabel *)contentLabel
{
if (!_contentLabel) {
_contentLabel = [[UILabel alloc] init];
_contentLabel.font = [UIFont systemFontOfSize:14];
_contentLabel.textColor = [UIColor blueColor];
_contentLabel.numberOfLines = 0;
_contentLabel.lineBreakMode = NSLineBreakByCharWrapping;
}
return _contentLabel;
}
@end
UITabelView的代理方法
#pragma mark - table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 100;
}
//如果tableView.estimatedRowHeight = 0,就执行这个方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [AutoLayoutCell heightWithString:cellContent];
}
//如果没设置tableView.estimatedRowHeight,就执行这个方法
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [AutoLayoutCell heightWithString:cellContent];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
AutoLayoutCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identify" forIndexPath:indexPath];
[cell setCellString:cellContent];
return cell;
}
Section高度
同样的方法也适用于UITableViewHeaderFooterView
优化提高
这个高度可以用hash表做一个缓存,下次不需要计算直接取出来用就可以了。
附上Demo:https://github.com/DuoLaiMao/DLMTableViewAutoLayout.git
网友评论