自定义不等高cell,详解步骤

一.创建一个继承与UITableViewCell的类

在让这个类的.h文件拥有一个模型属性,在.m文件拥有子控件的类型属性,这样就可以在layoutSubviewsset方法中拿到这些子控件,给它设置frame,赋值;

1.在下面方法中添加子控件

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
    // 添加子控件
    *******
}
  return self;
}

2.在layoutSubviews方法中设置frame;

- (void)layoutSubviews
{
    [super layoutSubviews];

    self.iconImageView.frame = self.status.iconFrame;
    self.nameLabel.frame = self.status.nameFrame;
    *******
}

3.在模型属性的set方法中给子控件设置数据

- (void)setStatus:(DXStatus *)status
{
    _status = status;
if (self.status.picture) {
         self.pictureImageView.hidden = NO;
         self.pictureImageView.image = [UIImage imageNamed:status.picture];
    }else {
        self.pictureImageView.hidden = YES;
    }
******

注意:因为涉及到根据标识符循环利用cell,所以在给子控件中赋值时候要判断这个cell是否有这个子控件,有if 就一定有else.

并且注意,是elseelse if区别,else意思是除了if外的其他情况,而else if是另外一种判断;表示还有其他可能情况;

二.新建一个模型

  • 1.给模型添加子控件的frame属性,用于传递给新建的类
  • 2.给模型添加plist文件中相对应的属性;
  • 3.给模型添加子控件的frame属性;
  • 4.给模型添加(cellHeight)cell行高属性;
  • 5.在模型中重写cellHeight的get方法,并在里面计算cell的行高;
    比如:
@property (nonatomic, copy) NSString *picture;
@property (nonatomic, assign) BOOL vip;
@property (nonatomic,assign) CGFloat cellHeight;
@property (nonatomic,assign) CGRect iconFrame;

声明属性需要特别注意:声明属性,起名字注意,不要跟系统自带的属性名字一样,比如在UITableViewCell中,它又一个imageView,那么你自定义UIImageView,不要用imageView作为属性名字,可以用iconImageView,如果你用这个imageView,可能会覆盖系统自带的属性,或者会出现问题,比如我用`UILabel *textLabel = [[UILabel alloc] init]`;那么UILabel系统内部有一个textLabel,这样会导致自己在给这个控件设置frame时候,出现和系统混乱问题,;

但是你可以用titleLabel,作为一个UILabel类型的名字,虽然UIButton内部有一个titleLabel属性,但是你现在没有用到UIButton
起名字要注意,一般要在后面加上控件的名称,比如声明一个UILabel类型的的属性,他名字最好是nameLabe,l

三.在控制器中需要做

  • 1.更改viewController继承为UITableViewController
  • 2.删除storyboard,添加UITableViewController控制器,更改它类为viewController;
  • 3.让控制器拥有一个数组属性,用来装模型;
  • 4.懒加载--数组属性重写get方法,在这个方法判断,如果属性为空,就加载plist文件(mainBundle -->数组-->遍历数组-->新模型数组-->赋值给当前属性 ),
  • 5.实现数据源方法
  • 1.一共有多少行
    tableView: numberOfRowsInSection:
  • 2.每一行长什么样子,并传递对应的模型数据给cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *ID = @"status";
    // 1.从缓存池中取
   DXStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    // 2.如果缓存池没有,自己创建
    if (!cell) {
        cell = [[DXStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
    }
    // 3.传递对应的模型数据给cell
    cell.status = self.statuses[indexPath.row];
    return cell;
}

6.实现代理方法,返回对应行高;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    DXStatus *status = self.statuses[indexPath.row];
    return status.cellHeight;
}

难点:为什么要在模型中计算子控件和cell的高度?

因为cell的高度是由代理方法设置的,而这个代理方法调用顺序先于layoutSubviews这个方法,而我们的cell高度又是依据子控件的高度而不同计算出来,因此从layoutSubviews这个方法中计算子控件frame,拿到cell高度,不能给代理方法用,因为调用顺序代理方法调用顺序先于layoutSubviews这个方法,因此在模型中给它一个cell高度属性,在属性set方法中计算子控件,算出每一个cell高度,在代理方法中,利用(indexPath.row)取出对应的模型对象,直接返回模型对象的cell属性,那么就会调用模型中cellHeight属性的get方法,就能拿到cellHeight;

技巧一:如果有的cell有图片,有的没有图片,先统一创建,然后再设置frame的时候进行判断,有的才给设置frame;

在set方法赋值的时候,也要进行判断这个cell是否有这个控件,如果有,就让它设置为显示,并进行赋值,如果没有,就让这个控件设置隐藏,不给它赋值;

技巧二:数据源方法的快速书写
一共有多少行这个方法tableView:numberOfRowsInSection:
先写返回值- (NSInteger)tableView就可过滤掉很多方法

每一行长什么样子
tableView: cellForRowAtIndexPath:
先写返回值 - (UITableViewCell *)tableView就可过滤掉很多方法

小知识点

1.contentView 和cell高度就差1,因为要显示分割线;
2.static NSString *ID = @“wine”;
用static修饰局部变量,这个局部变量就只创建一次,只分配一次内存,要不加static修饰字符串,每次调用这个方法就会重新创建一个局部变量;

不建议写外边,全局变量,会访问可以修改,但是注册某个标识,应该使用全局变量;
posted @ 2015-08-28 22:47  东邪喜毒  阅读(348)  评论(1编辑  收藏  举报