实用技术

UITableViewCell高度自适应

2017-02-06  本文已影响140人  wpf_register

参考文档

比较Masonry 和 SDAutoLayout 两个自动布局其实各有优劣,在使用上SDAutoLayout更方便简单,Masonry感觉功能更全面一些,并且SDAutoLayout 和 MyLayout 都是对frame的封装。

1. Masonry + 估算高度
- (UITableView *)tableView{
    if (!_tableView) {
        _tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, kWidth, kHeight ) style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;

        //直接用估算高度
        _tableView.rowHeight = UITableViewAutomaticDimension;
        _tableView.estimatedRowHeight = 80;
        
        _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
        [_tableView registerClass:[PUshMessageCell class] forCellReuseIdentifier:@"PUshMessageCell"];
        
    }
    return _tableView;
}

//*****cell 文件中主要方法*****//
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setup];
    }
    return self;
}
- (void)setup{
  
  //logo图片
    _logoImageView = [[UIImageView alloc]init];
    _logoImageView.image = [UIImage imageNamed:@"faghoo-logo"];
    [self.contentView addSubview:_logoImageView];
    [_logoImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(@28);
        make.left.equalTo(@10);
        make.width.height.equalTo(@40);
    }];

 //时间
    _timeLabel = [[UILabel alloc]init];
    [self.contentView addSubview:_timeLabel];
    [_timeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(_logoImageView.mas_top);
        make.centerX.equalTo(self.contentView);
    }];
   
   //文字背景图片
    UIImageView *containView = [[UIImageView alloc]init];
    containView.clipsToBounds = YES;
    UIImage *image = [UIImage imageNamed:@"qipao"];
    containView.image = [image resizableImageWithCapInsets: UIEdgeInsetsMake(50, 50, 50, 50) resizingMode:UIImageResizingModeStretch ];
    [self.contentView addSubview:containView];
        
    [containView mas_updateConstraints:^(MASConstraintMaker *make) {
        
        make.top.equalTo(_timeLabel.mas_bottom).offset(10);
        make.left.equalTo(_logoImageView.mas_right).offset(7);
        make.right.lessThanOrEqualTo(self.contentView).offset(-10);
        make.bottom.offset(-10).priorityLow();

    }];

    //文字Label
    _messageLabel = [[MLLinkLabel alloc]init];
    [containView addSubview:_messageLabel];
    _messageLabel.numberOfLines = 0;
    
   
   // _messageLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 10-40 -7- 25-20;
    
    [_messageLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.top.equalTo(containView.mas_top).offset(10);
        make.left.equalTo(containView.mas_left).offset(25);
        make.right.equalTo(containView.mas_right).offset(-10);
        make.bottom.equalTo(containView.mas_bottom).offset(-10);

    }];
   [_messageLabel setContentHuggingPriority:1000 forAxis:UILayoutConstraintAxisVertical];
    
   //设置label中链接方法
    [_messageLabel setDidClickLinkBlock:^(MLLink *link, NSString *linkText, MLLinkLabel *label) {
        if (link.linkType==MLLinkTypeURL) {
            
            NSString *url = [NSString stringWithFormat:@"%@",link.linkValue];
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
            
        }

    }];
}
2.Masonry/XIB + UITableView+FDTemplateLayoutCell

TableView如果用估算高度的话,可能会出现卡顿,系统性能有损耗较大。所以结合正确约束自动适应高度是比较合适的。

#import <UITableView+FDTemplateLayoutCell.h>
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    //有缓存
    return [tableView fd_heightForCellWithIdentifier:@"identifer" cacheByIndexPath:indexPath configuration:^(id cell) {
        // 配置 cell 的数据源,和 "cellForRow" 干的事一致,比如:
        cell.entity = self.feedEntities[indexPath.row];
       }];
    //无缓存
    return [tableView fd_heightForCellWithIdentifier:@"reuse identifer" configuration:^(id cell) {
        // Configure this cell with data, 
        //same as what you've done in "-tableView:cellForRowAtIndexPath:"
        // Like:
        cell.entity = self.feedEntities[indexPath.row];
       }];
}



//*****cell 文件中主要方法*****//
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setup];
    }
    return self;
}
- (void)setup{
    _godImageView = [[UIImageView alloc]init];
    [self.contentView addSubview:_godImageView];
    
   //图片
    [_godImageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(@12);
        make.left.equalTo(@12);
        make.width.height.equalTo(@46);
        make.bottom.equalTo(@-10).priorityLow();
    }];
    
   //标题
    _godTitle = [[UILabel alloc]init];
    [self.contentView addSubview:_godTitle];
    [_godTitle mas_makeConstraints:^(MASConstraintMaker *make){
       
        make.top.equalTo(@16);
        make.left.equalTo(_godImageView.mas_right).offset(10);
        make.right.lessThanOrEqualTo(self.mas_rightMargin);  
    }];
    
 //内容
    _contentMLabel = [[MLLabel alloc]init];
    _contentMLabel.numberOfLines = 0;
    _contentMLabel.lineSpacing = 5;
    [self.contentView addSubview:_contentMLabel];
    _contentMLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 63;
    [_contentMLabel mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.top.equalTo(_godTitle.mas_bottom).offset(7);
        make.left.equalTo(_godTitle);
        make.right.equalTo(self.contentView).offset(-12);
       make.bottom.equalTo(self.contentView).offset(-10);
        
    }];
Notes:

FDTemplateLayoutCell有两种计算高度的模式

  1. 是AutoLayout使用的-systemLayoutSizeFittingSize:
  2. 是Frame使用的-sizeThatFits:
    可以通过fd_enforceFrameLayout = YES 开启Frame模式,
    注意,开启Frame模式需要重写- (CGSize)sizeThatFits,
    如下:
    -(CGSize)sizeThatFits:(CGSize)size{
    return CGSizeMake(size.width, A+B+C+D+E+....);
    }
3. SDAutoLayout相关

比masonry易用性更强,对view,tableView等视图的约束更加便捷,UILabel,UIButton,UIScrollView都有相应的约束方法。
类似的链式编码 很简洁,同时对Cell高度自适应效果也很好,并且有高度缓存。

    self.view0 = [[UIView alloc]init];
    self.view1 = [[UIView alloc]init];
    self.view2 = [[UIView alloc]init];
    self.view3 = [[UIView alloc]init];
    self.view4 = [[UIView alloc]init];

    self.view1.sd_layout
    .leftSpaceToView(self.view0,10)
    .topEqualToView(self.view0)
    .heightRatioToView(self.view0,0.5)
    .widthIs(60);
    
    self.view3.sd_layout
    .leftSpaceToView(self.view0,10)
    .topSpaceToView(self.view1,0)
    .widthRatioToView(self.view1,1)
    .heightRatioToView(self.view0,0.5);
    
    self.view4.sd_layout
    .centerXEqualToView(self.view0)
    .centerYEqualToView(self.view0)
    .widthRatioToView(self.view0,0.5)
    .autoHeightRatio(1);
    //添加多个子视图
    [self.view sd_addSubviews:@[_view0,_view1,_view2,_view3,_view4]];
    
    //修改约束后要更新父图及子视图的约束
     [UIView animateWithDuration:0.5 animations:^{
        self.view0.sd_layout
        .widthRatioToView(self.view,_widthRatio);
     
        //一定要更新约束,否则没效果
        [self.view0 updateLayout];
        //如果不更新子视图,则子视图没有动画效果
        [self.view5 updateLayout];
        //也可以写成下面这样生新而局子视图
        //[self.view0 layoutSubviews];
     }];
//view0有两个子视图
self.view0.sd_layout
    .topSpaceToView(self.view,10)
    .leftSpaceToView(self.view,10)
    .rightSpaceToView(self.view,10);
    [self.view0 sd_addSubviews:@[self.view1,self.view2]];
    
    self.view1.sd_layout
    .topSpaceToView(self.view0,10)
    .leftSpaceToView(self.view0,10)
    .rightSpaceToView(self.view0,10)
    .autoHeightRatio(0);       //view1 为UILabel类型,自适应高度
    
    self.view2.sd_layout           
    .rightEqualToView(self.view1)
    .leftEqualToView(self.view1)
    .topSpaceToView(self.view1,10)
    .heightIs(30);
    //设置view或Cell 高度自适应 
    [self.view0 setupAutoHeightWithBottomView:self.view2 bottomMargin:10];  
  
    //单行label 自适应宽度
    self.view4.text = @"Label的宽度自适应的测试";
    self.view4.sd_layout
    .leftSpaceToView(self.view,10)
    .topSpaceToView(self.view3,10)
    .heightIs(30);
    //设置单行Label自适应的最大宽度
    [self.view4 setSingleLineAutoResizeWithMaxWidth:300];

    //button的自适应高度
    //A:
   [self.view3 setTitle:@"这是关于button的宽度自适应" forState:UIControlStateNormal];
    self.view3.sd_layout
    .centerXEqualToView(self.view)
    .topSpaceToView(self.view0,10);
    //设置button单行文字自适应padding为左右边距
    [self.view3 setupAutoSizeWithHorizontalPadding:10 buttonHeight:30];
    //B:
    UIButton *button = [[UIButton alloc]init];
    self.button = button ;
    [button setImage:[UIImage imageNamed:@"test0.jpg"] forState:UIControlStateNormal];
    [button setTitle:@"这是一个文字" forState:UIControlStateNormal];
    button.backgroundColor = [UIColor grayColor];
    button.titleLabel.backgroundColor = [UIColor redColor];//文字默认颜色可能为白色
    button.titleLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:button];
     
    button.sd_layout
    .topSpaceToView(self.view,10)
    .centerXEqualToView(self.view)
    .widthRatioToView(self.view,0.5)
    .autoHeightRatio(1);
    [self.view addSubview:button];
 
   //设置样式
    button.imageView.sd_layout
    .topSpaceToView(button,10)
    .centerXEqualToView(button)
    .widthRatioToView(button,0.8)
    .heightRatioToView(button,0.6);
    
    button.titleLabel.sd_layout
    .topSpaceToView(button.imageView,10)
    .rightSpaceToView(button,10)
    .leftSpaceToView(button,10)
    .bottomSpaceToView(button,10);
 UIView *view0 = [[UIView alloc]init];
    [self.view addSubview:view0];
    self.view0 = view0;
    view0.backgroundColor = [UIColor yellowColor];
    view0.sd_layout
    .leftSpaceToView(self.view,10)
    .rightSpaceToView(self.view,10)
    .topSpaceToView(self.button,10);
    
    NSMutableArray *arr = [NSMutableArray array];
    for (int i = 0; i<count; i++) {
        UIView *view = [[UIView alloc]init];
        [arr addObject:view];
        view.backgroundColor = [UIColor blueColor];
        [view0 addSubview:view]; 
        view.sd_layout.autoHeightRatio(0.3);
    }
    
    //子视图只设置高宽比例,
    //用下面两种方法可生成宽间距或等宽的view
    [view0 setupAutoMarginFlowItems:arr
               withPerRowItemsCount:3
                          itemWidth:100
                     verticalMargin:10
                  verticalEdgeInset:5 
                horizontalEdgeInset:5];
//    [view0 setupAutoWidthFlowItems:arr
//              withPerRowItemsCount:3
//                    verticalMargin:10
//                  horizontalMargin:10
//                 verticalEdgeInset:5 
//               horizontalEdgeInset:5];
 UIScrollView *scrollView = [[UIScrollView alloc]init];
 [self.view addSubview:scrollView];
 scrollView.sd_layout.spaceToSuperView(UIEdgeInsetsZero);
  [scrollView sd_addSubviews:@[_view0,_view1,_view2,_view3]];
    
    self.view0.sd_layout
    .topSpaceToView(scrollView,50)
    .centerXEqualToView(scrollView)
    .widthIs(200)
    .heightEqualToWidth();
    
    self.view1.sd_layout
    .topSpaceToView(self.view0,100)
    .leftSpaceToView(scrollView,30)
    .rightSpaceToView(scrollView, 30)
    .heightIs(100);
    
    self.view2.sd_layout
    .topSpaceToView(self.view1,100)
    .rightSpaceToView(scrollView,60)
    .leftSpaceToView(scrollView,60)
    .autoHeightRatio(0.4);
    
   self.view3.sd_layout
    .topSpaceToView(self.view2,100)
    .rightSpaceToView(scrollView,100)
    .leftSpaceToView(scrollView,100)
    .heightIs(100);
 
  [scrollView setupAutoContentSizeWithBottomView:self.view3 bottomMargin:10];
 UIView *contentView = [[UIView alloc]init];
 contentView.backgroundColor = [UIColor whiteColor];  
[self.scrollView addSubview:contentView];
    
    contentView.sd_layout
    .topSpaceToView(self.scrollView,0)
    .leftSpaceToView(self.scrollView,0)
    .rightEqualToView(self.scrollView);
    
    NSMutableArray *arr  = [NSMutableArray array];
    for (int i= 0; i < 100; i++) {
        UIView *view = [[UIView alloc]init];
        view.backgroundColor = [self randomColor];
        [contentView addSubview:view];
        view.sd_layout.autoHeightRatio(1);
        [arr addObject:view];
    }
    [contentView setupAutoWidthFlowItems:arr
                    withPerRowItemsCount:5
                          verticalMargin:10
                        horizontalMargin:10
                       verticalEdgeInset:10
                     horizontalEdgeInset:10 ];
//    [contentView setupAutoMarginFlowItems:arr
//                     withPerRowItemsCount:5
//                                itemWidth:50
//                           verticalMargin:10
//                        verticalEdgeInset:10
//                      horizontalEdgeInset:10 ];
    
    //如果scrollView 中子视图也要自适应则这样处理合适
    //将所有视图放到contentView中
    [self.scrollView setupAutoContentSizeWithBottomView:contentView bottomMargin:10];
//第一步设置正确的cell 约束
    UIView *view0 = [UIView new];
    view0.backgroundColor = [UIColor redColor];
    UIView *view1 = [UIView new];
    UILabel *lable = [UILabel new];
    UIView *view3 = [UIView new];
    /*******
     一定要先将视图添加到父视图后再添加约束,否则可能无效
     ********/
    [self.contentView sd_addSubviews:@[view0,view1,lable,view3,view4,view5]];

    view0.sd_layout
    .topSpaceToView(self.contentView,10)
    .leftSpaceToView(self.contentView,10)
    .widthIs(50)
    .heightIs(50);
    
    view1.sd_layout
    .topEqualToView(view0)
    .leftSpaceToView(view0,10)
    .rightSpaceToView(self.contentView,10)
    .heightIs(30);
    
    lable.sd_layout
    .leftEqualToView(view1)
    .topSpaceToView(view1,10)
    .rightSpaceToView(self.contentView,120)
    .autoHeightRatio(0);

    view3.sd_layout
    .leftSpaceToView(lable,10)
    .topSpaceToView(view1,10)
    .rightSpaceToView(self.contentView,10)
    .heightRatioToView(lable,1);
    //设置cell 高度自适应
    [self setupAutoHeightWithBottomView:view4 bottomMargin:10];

 //第二步代理方法返回Cell高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return     //推荐写法
 [self.tableView cellHeightForIndexPath:indexPath                                        model:self.dataSource[indexPath.row]
                                  keyPath:@"text"
                                cellClass:[DemoVC7Cell class]
                         contentViewWidth:[UIScreen mainScreen].bounds.size.width];
    /*
    //数据量小时可以这样写
    return
 [self.tableView cellHeightForIndexPath:indexPath 
                    cellContentViewWidth:[UIScreen mainScreen].bounds.size.width tableView:tableView];
     */
}

高度缓存

-(UITableViewCell *)tableView:(UITableView *)tableView 
           cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 //
//
//缓存高度,tableview滑动更加流畅
 [cell useCellFrameCacheWithIndexPath:indexPath tableView:tableView];
//
//
}
上一篇下一篇

猜你喜欢

热点阅读