前言
虽然在UITableView中可以直接拖控件的方式进行添加cell,但是这种方式有一个致命的缺点,那就是cell是固定的,而且cell的高度难以更改。在实际的开发中并不能满足我们的需求。比如以下:
在这个TableView中每一个cell中有一个显示时间的label,一个显示内容的button,一个显示头像的imageView 并且由于聊天内容的多少 每一个cell的高度都是动态改变的,显然系统提供的cell并不能满足需求!
与此类似的还有微博手机客户端,糗事百科客户端等等
以下是搭建此类UI界面的大概步骤,不涉及网络功能,和存储功能,所有的数据信息用plist文件配置。
1.1 根据数据建立数据模型
@interface CLWeiBo : NSObject @property (nonatomic,copy) NSString *text;//正文 @property (nonatomic,copy) NSString *icon;//头像 @property (nonatomic,copy) NSString *name;//昵称 @property (nonatomic,copy) NSString *picture;//图片 @property (nonatomic,assign,getter = isVip) BOOL *vip;//VIP
1.2 提供两个初始化方法
- (instancetype) initWithDict: (NSDictionary *)dict;//对象方法 + (instancetype) weiboWithDict: (NSDictionary *)dict;//类方法
方法内部实现就不再赘述了!
2.1 根据数据模型建立frame模型
之所以建立frame模型,是为了封装计算cell内各个控件位置的过程。这体现了OOP的编程思想!
在Frame模型中,各个控件的Frame会根据传递过来的数据模型进行计算设置,所以Frame模型中必须有一个数据模型属性,且计算各个控件的frame的过程应该放在模型数据属性的set方法中,并且在这里计算出cell的高度
@interface CLWeiBoFrame : NSObject /** * 头像的Frame 如果成员变量只允许类本身修改,应该把它声明成readonly,体现良好的编码习惯。 */ @property (nonatomic, assign, readonly)CGRect iconF; /** * 正文的frame */ @property (nonatomic, assign, readonly)CGRect textF; /** * VIP图标的frame */ @property (nonatomic, assign, readonly)CGRect vipF; /** * 昵称的Frame */ @property (nonatomic, assign, readonly)CGRect nameF; /** * 图片的Frame */ @property (nonatomic, assign, readonly)CGRectpictureF; /** * 数据模型 */ @property (nonatomic, strong) CLWeiBo *weibo; /** * cell的高度 */ @property (nonatomic, assign, readonly) CGFloat cellHeight; @end
3.1 新建CLWeiBocell并且继承自UITableViewCell
有frame模型类型的成员属性,用来对cell内的各个控件设置frame 以及数据
因为frame模型中有一个数据模型 所以这里无需再引入数据模型
@property (nonatomic, strong) CLWeiBoFrame *weiboFrame;
并且提供一个类方法,外界调用建立cell的接口,需要传入参数tableView 。传入tableView参数是为了能够取得tableView内的cell队列循环利用cell
+ (instancetype)cellWithTableView:(UITableView*)tableView { static NSString *ID = @"weibo"; CLWeiBoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) { cell = [[CLWeiBoCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } return cell; }
3.2 重写系统的cell的构造方法 在初始化cell对象的时候调用,在这个方法中添加cell的子控件
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:stylereuseIdentifier:reuseIdentifier];
if (self) {
// 1.头像
//在这里只是声明并添加控件 控件的frame设置以及数据的设置放在frame模型属性的set方法中 在拿到frame模型数据后同时设置cell内子控件的frame和数据
UIImageView *iconView = [[UIImageView alloc]init];
[self.contentView addSubview:iconView];
self.iconView = iconView;
// 2.昵称
UILabel *nameView = [[UILabel alloc] init];
nameView.font = MJNameFont;
[self.contentView addSubview:nameView];
self.nameView = nameView;
// 3.会员图标
UIImageView *vipView = [[UIImageView alloc]init];
vipView.image = [UIImage imageNamed:@"vip"];
[self.contentView addSubview:vipView];
self.vipView = vipView;
// 4.正文
UILabel *textView = [[UILabel alloc] init];
textView.numberOfLines = 0;
textView.font = MJTextFont;
[self.contentView addSubview:textView];
self.textView = textView;
// 5.配图
UIImageView *pictureView = [[UIImageViewalloc] init];
[self.contentView addSubview:pictureView];
self.pictureView = pictureView; }
return self; } //frame模型数据 变量的set方法 在这里接到外界的frame模型数据的同时设置frame和显示数据 - (void) setCLWeiBoFrame:(MJStatusFrame *)statusFrame {
_statusFrame = statusFrame;
// 1.设置数据 [self settingData];
// 2.设置frame [self settingFrame]; }
4.新建控制器继承UITableViewController 并且遵守UITableView数据源协议
4.1 在控制器中声明frame模型属性数组
/** * 存放所有cell的frame模型数据 */ @property (nonatomic, strong) NSArray *weiboFrames; //在weiboFrames的set方法中完成plist文件中的字典数据向模型数据转换的过程 - (NSArray *)statusFrames {
if (_weiboframes == nil)
{
// 初始化
// 1.获得plist的全路径
NSString *path = [[NSBundle mainBundle]pathForResource:@"statuses.plist" ofType:nil];
// 2.加载数组
NSArray *dictArray = [NSArrayarrayWithContentsOfFile:path];
// 3.将dictArray里面的所有字典转成模型对象,放到新的数组中
NSMutableArray *weibosFrameArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
// 3.1.创建CLWeiBo模型对象
CLWeiBo *weibo = [CLWeiBo weiboWithDict:dict];
// 3.2.创建CLWeiBoFrame模型对象
CLWeiBoFrame *weiboFrame = [[CLWeiBoFrame alloc] init];
weiboFrame.weibo = weibo;
// 3.2.添加模型对象到数组中 [weibosFrameArray addObject:weiboFrame];
}
// 4.赋值
_weiboframes = _weibosframeArray;
}
return _weiboframes; }
4.2 实现数据源方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.statusFrames.count; } - (UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
// 1.创建cell
MJStatusCell *cell = [MJStatusCellcellWithTableView:tableView];
// 2.在这里已经算好了cell的高度
cell.statusFrame =self.statusFrames[indexPath.row];
// 3.返回cell
return cell; }
4.3 实现代理方法
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 取出这行对应的frame模型
MJStatusFrame *statusFrame =self.statusFrames[indexPath.row];
return statusFrame.cellHeight; }
到此完毕!