美文网首页iOS开发知识小集
UItableViewCell使用AutoLayout自适应高度

UItableViewCell使用AutoLayout自适应高度

作者: 多来猫 | 来源:发表于2018-06-09 15:20 被阅读647次

    关于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

    相关文章

      网友评论

        本文标题:UItableViewCell使用AutoLayout自适应高度

        本文链接:https://www.haomeiwen.com/subject/atvteftx.html