免费开源的iOS开发学习平台

UITableView详解:13-动态调整Cell高度(代码)

在iOS8推出self-sizing之前,如果涉及到单元格Cell高度的动态调整,则需要通过代码来实现。实现的思路就是根据单元格cell内部需要填充的内容,来动态计算出所需的高度。这就需要在数据模型类中,增加一个有关单元格cell高度的属性,同时把这个高度属性返回到表视图的代理方法中。

计算文字所需的高度

为了计算文字的高度,需要新增一个NSString类型的分类,并添加一个方法,该方法可以根据输入的文字内容text,字体大小font,以及所需的宽度width,计算出所需的高度。

  • 在NSString+Extent.h文件中,添加用于计算内文本高度的方法声明。注意,这里要注意导入UIKit框架。
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h> 
@interface NSString (Extent)
- (CGFloat) heightWithText:(NSString *) text FontSize:(UIFont *) font LabelWidth:(CGFloat) width;
@end
  • 在NSString+Extent.m文件中,实现计算高度的方法
- (CGFloat) heightWithText:(NSString *) text FontSize:(UIFont *) font LabelWidth:(CGFloat) width{
    NSDictionary * attributes = @{NSFontAttributeName : font};    
    CGSize contentSize = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT)
                                            options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                         attributes:attributes
                                            context:nil].size;
    return contentSize.height   ;
}

完善数据模型

在MYModel.h数据模型类中,增加一个高度属性cellLabelHeight,同样要注意导入UIKit框架。

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface MYModel : NSObject
@property (nonatomic,copy) NSString *profileImageName;//头像
@property (nonatomic,copy) NSString *userName;//发送用户
@property (nonatomic,copy) NSString *source;//设备来源
@property (nonatomic,copy) NSString *content;//内容
@property (nonatomic,copy) NSString *iconName;//小图标
@property (nonatomic,assign) CGFloat cellLabelHeight;
+(instancetype)myCellModel;
@end

myCellModel方法中,设置一个随机数,这样实例化后,content属性中的文字内容会随机生成。同时在该方法中,调用NSString+Extent.h中提供的计算文字高度的方法,计算结果存放在contentLabelHeight中,最后再根据单元格cell的实际布局(需要考虑其他控件)得到单元格cell的最终高度cellLabelHeight

#import "NSObject+Extent.h"
+(instancetype)myCellModel {
    MYModel *cellModel = [[MYModel alloc]init];    
    cellModel.userName = @"99iOS";
    cellModel.profileImageName = @"99logo";
    cellModel.iconName = @"99logo";
    cellModel.source = @"来自99iOS的iPhone 7";
    //创建随机数,根据不同的内容显示不同高度的cell
    int random = arc4random_uniform(2);
    if (random == 1) {
        cellModel.content = @"苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路苹果iOS开发进阶之路";
    }else{
        cellModel.content = @"苹果iOS开发进阶之路";
    }
    //设置高度
    CGFloat contentLabelHeight = [cellModel.content heightWithText:cellModel.content FontSize:[UIFont systemFontOfSize:17.0] LabelWidth:[UIScreen mainScreen].bounds.size.width];
    //计算出来的高度需要多加一点,否则会显示不全
    cellModel.cellLabelHeight = 82.5 + 10 + contentLabelHeight + 10 + 8;
        return cellModel;
}

动态设置单元格的高度

在UITableViewDelegate协议中的heightForRowAtIndexPath:方法,可以根据indexPath参数,为每一个单元格设置不同的高度。因此,我们可以根据indexPath从数据源中获取到每个单元格对应的MYModel对象,并获取其中的cellLabelHeight属性作为方法的返回值,从而实现单元格高度的动态调整。

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
  • 在控制器类中,添加一个dataArray数组,用来存放所有单元格需要的数据。
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
@property (nonatomic,strong) UITableView * tableView;
@property (nonatomic,copy) NSMutableArray *dataArray;
@end
- (NSMutableArray *)dataArray {
    if (_dataArray == nil) {    
        _dataArray = [NSMutableArray array];        
        for (int i=0; i < 10; i++) {
            MYModel *cellData = [MYModel myCellModel];            
            [_dataArray addObject:cellData];
        }        
    }
    return _dataArray;
}
  • 在tableView:heightForRowAtIndexPath方法中,取出数据模型对象中的cellLabelHeight属性,并作为单元格Cell的高度返回。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    MYModel *cellData = self.dataArray[indexPath.row];
    return cellData.cellLabelHeight ;
}

运行效果:

示例代码

https://github.com/99ios/8.2.13