前言:在iOS程序开发中,
TableView
的实用是最常见的,在一些比较特殊的需求下,必须展示的是用户评论信息,或发布的微博,这样的情况下,固定高度的cell
显然是不能实现我们的需求,这就需要我们根据需要展示的内容,动态的设置cell
的高度.下面是我做的一个Demo
, 我们一起来做一下如何去实现这样的功能,希望能够对你起到一定的帮助.下面是效果图.
1 . 首先来我们分析一下这个需求,很显然这是一个可以滑动的列表,很自然我们就会想到用tableView
去实现.在这个列表上面,每一个cell
存放一条用户发送的数据,这些数据包括用户的名字,用户发送的正文内容,另外就是有一些是有配图的,有一些是没配图的.另外就是单元格的高度会随着内容的变化而变大或者变小.分析完这些,那我们开始撸代码,既然我们没有做过自适应高度的需求,那我们总做过高度固定的单元格吧,那就索性先给一个固定高度,然后再去调整. 接着我们去创建viewController.并且给tableView注册自定义单元格.
self.tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain];
[self.tableView registerClass:[AdaptiveTableViewCell class] forCellReuseIdentifier:identifier];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView];
2 . 创建model
类,添加数据源,并且保存在数组中.这个数据源我是写在了,plist
文件当中,并且使用cocoaPods
导入MJExtension
进行数据转模型.
#pragma mark - 懒加载
- (NSArray *)dataSource {
if (!_dataSource) {
self.dataSource = [AdaptiveModel mj_objectArrayWithFilename:@"ModelList.plist"];
}
return _dataSource;
}
3 . 在自定义的cell
中添加重写初始化方法,添加子控件.
// 重写初始化方法
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self setupView];
}
return self;
}
// 添加子控件
- (void)setupView {
UILabel *nameLabel = [UILabel new];
[self.contentView addSubview:nameLabel];
nameLabel.textColor = [UIColor orangeColor];
nameLabel.font = [UIFont systemFontOfSize:17];
self.nameLabel = nameLabel;
UILabel *textLabel = [[UILabel alloc] init];
textLabel.numberOfLines = 0;
textLabel.font = [UIFont systemFontOfSize:14];
[self.contentView addSubview:textLabel];
self.text_Label = textLabel;
UIImageView *pictureView = [[UIImageView alloc] init];
[self.contentView addSubview:pictureView];
self.picthreView = pictureView;
}
4 . 注意在添加子控件的时候我是没有给出控件的frame
的.因为单元格的高度要根据需要展示的内容来动态计算的,那我们就在model
类里面动态的计算出控件的frame
和cell
的高度,并且保存在model类中. 注意在model中要把#import <Foundation/Foundation.h>
框架更改成#import <UIKit/UIKit.h>
否则没法添加CGRect
属性.
#import <UIKit/UIKit.h>
// 模型
@interface AdaptiveModel : NSObject
@property (nonatomic, copy) NSString *name; // 昵称
@property (nonatomic, copy) NSString *text; // 正文
@property (nonatomic, copy) NSString *picture; // 图片
@property (nonatomic, assign) CGRect nameFrame; // 昵称的frame
@property (nonatomic, assign) CGRect textFrame; // 正文的frame
@property (nonatomic, assign) CGRect pictureFrame; // 图片的frame
@property (nonatomic, assign) CGFloat cellHeight; // 单元格高度
@end
5 .然后再model.m
中懒加载计算出各个控件的frame
和cell
的高度
#import "AdaptiveModel.h"
#define Space 10 // 间距
@implementation AdaptiveModel
// 懒加载
- (CGFloat)cellHeight {
if (_cellHeight == 0) {
CGFloat nameX = Space;
CGFloat namey = Space;
// 获取文字宽度
// CGSize nameSzie = [self getLabalSizeWithLabel:self.nameLabel];
NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:17]};
CGSize nameSize = [self.name sizeWithAttributes:attribute];
self.nameFrame = CGRectMake(nameX, namey, nameSize.width, nameSize.height);
// 正文
CGFloat textW = [UIScreen mainScreen].bounds.size.width - Space * 2;
NSDictionary *attribute1 = @{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGSize textsize = [self.text boundingRectWithSize:CGSizeMake(textW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute1 context:nil].size;
// CGFloat textH = [self getLabelSizeWithLabel:self.text_Label width:textW];
self.textFrame = CGRectMake(Space, CGRectGetMaxY(self.nameFrame) + Space, textW, textsize.height);
// 图片
if (self.picture) {
self.pictureFrame = CGRectMake(Space, CGRectGetMaxY(self.textFrame) + Space, 100, 100);
_cellHeight = CGRectGetMaxY(self.pictureFrame) + Space;
} else {
_cellHeight = CGRectGetMaxY(self.textFrame) + Space;
}
}
return _cellHeight;
}
@end
注意事项:
注意在此时用到了2个方法,第一个是获取文字尺寸,这个方法仅限于label
没有换行,需要获取文字宽度时使用.需要注意的地方就是设置的font
和你label
控件设置的font
必须是一致的.
// 获取文字宽度
NSDictionary *attribute = @{NSFontAttributeName : [UIFont systemFontOfSize:17]};
CGSize nameSize = [self.name sizeWithAttributes:attribute];
第二个方法也是获取文字尺寸,和第一个方法不同的是这个是可以换行的,需要注意的是不仅要设置
font
和你设置的label
的font
必须是一致的,还要给它设置一个最大的宽度,告诉它最大宽度时多少,才会自动换行.
// 正文
CGFloat textW = [UIScreen mainScreen].bounds.size.width - Space * 2;
NSDictionary *attribute1 = @{NSFontAttributeName: [UIFont systemFontOfSize:14]};
CGSize textsize = [self.text boundingRectWithSize:CGSizeMake(textW, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attribute1 context:nil].size;
6 .接下来我们计算好了cell的高度,就在tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
这个方法中设置cell
的高度就可以了.
// 设置单元格高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
AdaptiveModel *model = self.dataSource[indexPath.row];
return model.cellHeight;
}
7 . 设置单元格,给单元格上的控件赋值
// 设置单元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
AdaptiveTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
// 传递数组模型
cell.model = self.dataSource[indexPath.row];
return cell;
}
8 .在自定义的cell
里面重写属性的setter方法,给子控件赋值,并且设置控件的frame
// 重写属性的setter方法
- (void)setModel:(AdaptiveModel *)model {
if (_model != model) {
_model = model;
}
self.nameLabel.text = model.name;
self.text_Label.text = model.text;
if (model.picture) { // 有图片
self.picthreView.hidden = NO;
self.picthreView.image = [UIImage imageNamed:model.picture];
} else { // 没有图片
self.picthreView.hidden = YES;
}
// 设置控件的frame
self.nameLabel.frame = self.model.nameFrame;
self.text_Label.frame = self.model.textFrame;
self.picthreView.frame = self.model.pictureFrame;
}
总结:以上就是自适应
TableViewCell
的全过程,我们可以得出以下的结论,要想去实现tableView
自适应高度,首先我们需要计算出model
中各个控件的frame
和所需要的cell
的高度.然后再设置单元格高度的方法中,设置单元格所需要的高度.最后再把各个控件的frame
传递到cell
中来设置.当然还有其他的实现方法, 我这里只是给出了一个思路,具体怎么实现,还需要你自己去动脑子思考,希望能够对你起到一定的帮助作用.
另附gitHub下载地址