自适应TableViewCell(纯代码)

前言:在iOS程序开发中,TableView的实用是最常见的,在一些比较特殊的需求下,必须展示的是用户评论信息,或发布的微博,这样的情况下,固定高度的cell显然是不能实现我们的需求,这就需要我们根据需要展示的内容,动态的设置cell的高度.下面是我做的一个Demo, 我们一起来做一下如何去实现这样的功能,希望能够对你起到一定的帮助.下面是效果图.

图1.gif

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类里面动态的计算出控件的framecell的高度,并且保存在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中懒加载计算出各个控件的framecell的高度

#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和你设置的labelfont必须是一致的,还要给它设置一个最大的宽度,告诉它最大宽度时多少,才会自动换行.

  // 正文
        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下载地址

下一篇:自适应TableViewCell(XIB)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 概述在iOS开发中UITableView可以说是使用最广泛的控件,我们平时使用的软件中到处都可以看到它的影子,类似...
    liudhkk阅读 8,833评论 3 38
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,596评论 4 59
  • 最近不忙才想起来要好好整理之前的项目了。诚然其中遇到了许许多多得问题,但是当时都是没有太多的去关注,现想起来真是浪...
    Hflydragon阅读 145评论 0 0
  • 也许每一个男子全都有过这样的两个女人,至少两个。娶了红玫瑰,久而久之,红的变成了墙上的一抹蚊子血,白的还是“床前明...
    简单谈谈阅读 248评论 0 0
  • 写点什么呢?今天才是第三天。都已经有了不知道该说什么的感觉了。写自己身边发生的事吧,又觉得身边的事太小,不值...
    谷喵儿阅读 234评论 0 0