自定义不等高的cell
1.给模型增加frame数据(纯代码)
让ViewController继承UITableViewController,移除storyboard中的ViewController,新建一个UITableViewController让其与ViewController建立关联。
@interface ViewController:UITableViewController
在ViewController.m文件中实现UITableView代理的这个方法,这个方法会返回cell的高度,所以需要在返回高度前计算出cell的高度。
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
AZStatus *status=self.statuses[indexPath.row];
return status.cellHeight;
}
- 在status数据模型中计算出所有控件frame,只有模型数据知道哪些控件需要显示,这个方法会经常调用,考虑到性能对其进行判断,只有当第一次调用时才会计算。
- (CGFloat)cellHeight
{
if (_cellHeight==0) {
CGFloat margin=10;
...
// 图片frame
if (self.picture) {//有配图
CGFloat picX=margin*3;
CGFloat picY=CGRectGetMaxY(self.textFrame)+margin;
CGFloat picWH=200;
self.pictureFrame=CGRectMake(picX, picY, picWH, picWH);
_cellHeight=CGRectGetMaxY(self.pictureFrame)+margin;
}else{//无配图
_cellHeight=CGRectGetMaxY(self.textFrame)+margin;
}
}
return _cellHeight;
}
- 添加控件
-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self=[super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
...
//配图
UIImageView *pictureView=[[UIImageView alloc]init];
[self.contentView addSubview:pictureView];
self.picture1View=pictureView;
}
- 在AZStatusCell.h文件中引用模型
#import <UIKit/UIKit.h>
@class AZStatus;
@interface AZStatusCell : UITableViewCell
/*模型数据*/
@property(nonatomic,strong)AZStatus *status;
@end
- 在模型的set方法中给控件注入数据,同时也可以确定frame,和在layoutSubViews中确定frame效果一致
-(void)setStatus:(AZStatus *)status
{
_status=status;
// 设置数据
...
// 配图
if (status.picture) {
self.picture1View.hidden=NO;
self.picture1View.image=[UIImage imageNamed:status.picture];
}else{
self.picture1View.hidden=YES;
}
//设置frame
self.iconView.frame=status.iconFrame;
self.nameLabel.frame=status.nameFrame;
self.text_Label.frame=status.textFrame;
self.vipView.frame=status.vipFrame;
self.picture1View.frame=status.pictureFrame;
}
2.storyboard动态cell实现(iOS8以后)
- 在stroyboard的动态cell中添加所有的子控件
-
将cell中所有的子控件和AZStatusCell.m文件中的属性建立好连线,并将图片的约束也建立好连线
- 在status模型的set方法中,通过图片高度的约束控制图片显示与隐藏,上方间隙的约束的调整来控制所有cell下方的间隙一致
-(void)setStatus:(AZStatus *)status
{
_status=status;
// 设置数据
...
// 配图
if (status.picture) {
self.picture1View.hidden=NO;
self.picture1View.image=[UIImage imageNamed:status.picture];
self.pictureTop.constant=10;
self.pictureHeight.constant=100;
}else{
self.picture1View.hidden=YES;
self.pictureHeight.constant=0;
self.pictureTop.constant=0;
}
}
- 设置tableViewCell的真实行高和估算行高
// self-sizing(iOS8以后,两个方法一起使用)
// 设置tableView的高度为根据设定的约束自动计算
self.tableView.rowHeight=UITableViewAutomaticDimension;
// 设置tableView的估算高度
self.tableView.estimatedRowHeight=44;
3.如果要支持iOS8之前
- 如果cell内部有自动换行的label,需要设置preferredMaxLayoutWidth属性
- (void)awakeFromNib
{
// 手动设置文字的最大宽度(目的是:让label知道自己文字的最大宽度,进而能够计算出自己的frame)
self.text_label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
}
- 设置tableView的cell估算高度
// 告诉tableView所有cell的估算高度(设置了估算高度,就可以减少tableView:heightForRowAtIndexPath:方法的调用次数)
self.tableView.estimatedRowHeight = 200;
- 在代理方法中计算cell的高度
AZStatusCell *cell;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 创建一个临时的cell(cell的作用:根据模型数据布局所有的子控件,进而计算出cell的高度)
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:ID];
}
// 设置模型数据
cell.status = self.statuses[indexPath.row];
return cell.height;
}
- (CGFloat)height
{
// 强制布局cell内部的所有子控件(label根据文字多少计算出自己最真实的尺寸)
[self layoutIfNeeded];
// 计算cell的高度
if (self.status.picture) {
return CGRectGetMaxY(self.pictureImageView.frame) + 10;
} else {
return CGRectGetMaxY(self.text_label.frame) + 10;
}
}