关于Cell高度自适应的解决方案(非三方库)

继上篇文章说起cell高度的自适应起,已经好久了,上一篇是介绍了如何使用FDTemplateLayoutCell这个第三方库来解决。但是这毕竟是别人的东西,好用是好用,在遇到某些需求的时候还是不如自己写的好控制。

项目新版本也告一段落了,在项目中也正好有这种需求,刚开始我也是打算直接用上面提到库解决的,但是后来发现行不通,于是在查阅资料以及咨询大神后,得出一套适用于绝大多数场景的方案。

以我们公司项目为例,是一个社区的时间线的需求,类似QQ空间那种,很常见也是最经典的cell高度自适应需求的例子。

大神请轻喷(其实我也挺慌的),只为和我一样的菜鸟少走弯路,欢迎提出意见(讲真,我觉得这种方法很2b,太麻烦了)。

进入正题

先看效果图
1.png
2.png
3.png
上代码

其实实现最重要的就一个类,负责根据数据源计算cell中各个控件的frame的类

SmartCellFrame.h
#import <Foundation/Foundation.h>
#import "SmartModel.h"

@interface SmartCellFrame : NSObject

@property (nonatomic,assign) CGRect nameFrame;
@property (nonatomic,assign) CGRect dateFrame;
@property (nonatomic,assign) CGRect headShowFrame;
@property (nonatomic,assign) CGRect contentFrame;
@property (nonatomic,assign) CGRect addressFrame;
@property (nonatomic,assign) CGRect imagesFrame;

@property (nonatomic,strong) SmartModel *model; //数据源
@property (nonatomic,assign) CGFloat imageSize;   //每张图片的size
@property (nonatomic,assign) CGFloat cellHeight;   //cell的高度

@end

定义了各个控件的frame,简单起见,我只定义了6个,但是不管多少个原理都是一样的。

SmartCellFrame.m
#import "SmartCellFrame.h"

@implementation SmartCellFrame

-(void)setModel:(SmartModel *)model{
_model = model;

CGFloat margin = 15;   //边距

CGFloat screenWith = [UIScreen mainScreen].bounds.size.width;

//依次计算各个控件frame;

//头像的frame
CGFloat headx = margin;
CGFloat heady = margin;
CGFloat headw = 46;
CGFloat headh = 46;
_headShowFrame = CGRectMake(headx, heady, headw, headh);

CGFloat namex = headx+headw+10;
CGFloat namey = heady+5;
CGFloat namew = screenWith-namex-margin;
CGFloat nameh = 20;
_nameFrame = CGRectMake(namex, namey, namew, nameh);

CGFloat datex = namex;
CGFloat datey = heady+headh-20;
CGFloat datew = 200;
CGFloat dateh = 20;
_dateFrame = CGRectMake(datex, datey, datew, dateh);

CGFloat contentx = margin;
CGFloat contenty = heady+headh+margin;
CGFloat contentw = screenWith-2*margin;
CGFloat contenth = 0;

CGSize contentSize = [model.content boundingRectWithSize:CGSizeMake(contentw, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIFont systemFontOfSize:16],NSFontAttributeName,nil] context:nil].size;
contenth = contentSize.height;

_contentFrame = CGRectMake(contentx, contenty, contentw, contenth);

CGFloat imageListx = contentx;
CGFloat imageListy = contenty+contenth+margin;
CGFloat imageListw = (screenWith - margin-10-15);
CGFloat imageListh = 0.0;
NSInteger count = [model.images count];

_imageSize = imageListw/3;
CGFloat imageMargin = 2;

if (count>9) {
    count =9;
}
if (count==0) {
    imageListh = 0.0;
}
if (count==1) {
    CGFloat maxH = _imageSize*2;
    Image *image = model.images[0];
    if (image.height>=image.width) {
        //高度大于宽,以高度为准
        if(image.height<=maxH){
            imageListh = image.height;
            imageListw = image.width;
        }
        if (image.height>maxH) {
            imageListh = maxH;
            imageListw = image.width*(imageListh/image.height);
        }
    }
    
    if (image.height<image.width) {
        if (image.width<=maxH) {
            imageListh = image.height;
            imageListw = image.width;
        }
        if (image.width>maxH) {
            imageListw = maxH;
            imageListh = image.height*(imageListw/image.width);
        }
    }
}

if (count>1&&count<=3) {
    imageListh = _imageSize+imageMargin;
}
if (count>3&&count<=6) {
    imageListh = imageMargin +_imageSize*2;
}
if (count>6&&count<=9) {
    imageListh = imageMargin*2 +_imageSize*3;
}

_imagesFrame = CGRectMake(imageListx, imageListy, imageListw, imageListh);

CGFloat addressx = margin;
CGFloat addressy = imageListy+imageListh+margin;
CGFloat addressw = 200;
CGFloat addressh = 20;
_addressFrame  = CGRectMake(addressx, addressy, addressw, addressh);

//计算cell高度
_cellHeight =addressy+addressh+margin;
}

@end

这里计算frame的时候很多我是直接写死的大小,能写死的就写死吧,有变动需求的可以根据服务端返回的数据来变动,可参考上面content文本计算高度的方式,另外,图片的大小,一般来说最多就是九宫格,一张图片时做特殊处理,这个时候服务端最好能返回图片的尺寸。
最重要的类就是上面的了,其实也不难。

SmartHeightCellViewController.m 控制器类
#import "SmartHeightCellViewController.h"
#import "SmartModel.h"
#import "SmartTableViewCell.h"

@interface SmartHeightCellViewController ()<UITableViewDataSource,UITableViewDelegate>

@property (nonatomic,strong) UITableView *table;

@property (nonatomic,strong) NSMutableArray<SmartCellFrame *> *tableDatas;

@end

@implementation SmartHeightCellViewController

-(void)viewDidLoad{
    self.view.backgroundColor = [UIColor colorWithRed:0.980 green:0.980 blue:0.980 alpha:1.00];
    self.title = @"cell高度自适应";
    [self configdatas];
    [self configTable];
}

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return [_tableDatas count];
}

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

SmartTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"smart"];
if (cell==nil) {
    cell = [[SmartTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"smart"];
}
    //给cell设置model,cell的代码见下面
    [cell setCellFrame:_tableDatas[indexPath.row]];
    return cell;

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
      //这里就是给cell设置高度的地方,直接取我们算好的高度
      return _tableDatas[indexPath.row].cellHeight;
}

//最主要就是这个方法了
-(void)configdatas{
    _tableDatas = [[NSMutableArray alloc] init];
    NSArray *models = [SmartModel models]; //这个是我自己写的生成model的方法,可无视

    //这里将model转化为上面提到的计算的frame的类,这个类里就包含了cell里所有的布局信息以及cell的高度
    for (SmartModel *model in models) {
    SmartCellFrame *frame = [[SmartCellFrame alloc] init];
    [frame setModel:model];
    [_tableDatas addObject:frame];
  }

}

-(void)configTable{
     //初始化UITable,我是用的代码写的(原谅本人不会用sb)
    _table = [[UITableView alloc] init];
    _table.delegate = self;
    _table.dataSource = self;
    _table.backgroundColor = [UIColor whiteColor];
    [self.view addSubview:_table];
    [_table mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
}

@end

上面注释相信已经写的很详细了,就一个UITable,我不信有人看不懂或者懒得看的(这特么才几行代码你J就懒得看?),下面就是cell的代码

SmartTableViewCell.h
#import <UIKit/UIKit.h>
#import "SmartCellFrame.h"

@interface SmartTableViewCell : UITableViewCell

@property (nonatomic,strong) UIImageView *head;  
@property (nonatomic,strong) UILabel *name;
@property (nonatomic,strong) UILabel *date;
@property (nonatomic,strong) UILabel *content;
@property (nonatomic,strong) UIView *images;
@property (nonatomic,strong) UILabel *address;

@property (nonatomic,strong) SmartCellFrame *cellFrame;//计算frame的类,其实也含有数据源model

@end
SmartTableViewCell.m
#import "SmartTableViewCell.h"

@interface SmartTableViewCell ()

@property (nonatomic,strong) NSMutableArray *imageViews;
@property (nonatomic,strong) NSArray *imagesArr;

@end

@implementation SmartTableViewCell

-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
    
        self.contentView.backgroundColor = [UIColor whiteColor];
        self.selectionStyle = UITableViewCellSelectionStyleNone;
    
        [self setUp];
}

  return self;
}

-(void)setUp{
    _head = [[UIImageView alloc] init];
    _head.layer.masksToBounds = YES;
    _head.layer.cornerRadius = 23;
    _head.contentMode = UIViewContentModeScaleAspectFill;
    [self.contentView addSubview:_head];

    _name = [[UILabel alloc] init];
    _name.font = [UIFont systemFontOfSize:16];
    _name.textColor = [UIColor colorWithRed:1.000 green:0.251 blue:0.506 alpha:1.00];
    [self.contentView addSubview:_name];

    _date = [[UILabel alloc] init];
    _date.font = [UIFont systemFontOfSize:12];
    _date.textColor = [UIColor colorWithRed:1.000 green:0.502 blue:0.671 alpha:1.00];
    [self.contentView addSubview:_date];

    _content = [[UILabel alloc] init];
    _content.numberOfLines = 0;
    _content.font = [UIFont systemFontOfSize:16];
    _content.textColor = [UIColor colorWithRed:0.129 green:0.129 blue:0.129 alpha:1.00];
    [self.contentView addSubview:_content];

    _address = [[UILabel alloc] init];
    _address.font = [UIFont systemFontOfSize:12];
    _address.textColor = [UIColor colorWithRed:0.459 green:0.459 blue:0.459 alpha:1.00];
    [self.contentView addSubview:_address];

    _images = [[UIView alloc] init];
    _images.backgroundColor = [UIColor whiteColor];
    [self.contentView addSubview:_images];

    _imageViews = [[NSMutableArray alloc] init];
    for (int i=0; i<9; i++) {
        UIImageView *imageview = [[UIImageView alloc] init];
        imageview.backgroundColor = [UIColor colorWithRed:0.933 green:0.933 blue:0.933 alpha:1.00];
        [_imageViews addObject:imageview];
    }
}

//  最主要的就是这个类了
-(void)setCellFrame:(SmartCellFrame *)cellFrame{
    _cellFrame = cellFrame;
    _head.frame = cellFrame.headShowFrame;
    _name.frame = cellFrame.nameFrame;
    _date.frame = cellFrame.dateFrame;
    _content.frame = cellFrame.contentFrame;
    _images.frame = cellFrame.imagesFrame;
    _address.frame = cellFrame.addressFrame;

    _head.image = [UIImage imageNamed:cellFrame.model.headShowURL];
    _name.text = cellFrame.model.name;
    _date.text = cellFrame.model.date;
    _content.text = cellFrame.model.content;
    _address.text = cellFrame.model.address;

    _imagesArr = cellFrame.model.images;
    [self setUpImageViews];
}

//这个是布局图片的,挺简单的,我就不多说了
-(void)setUpImageViews{

    for (UIImageView *view in _images.subviews) {
        [view removeFromSuperview];
  }

    NSInteger count = [_imagesArr count];

    if (count==0) {
        return;
    }

    if (count==1) {
        UIImageView *imageView = _imageViews[0];
        Image *image = _imagesArr[0];
        imageView.layer.masksToBounds = YES;
        imageView.contentMode = UIViewContentModeScaleAspectFit;
    
        imageView.image = [UIImage imageNamed:image.imageURL];
    
        imageView.frame = CGRectMake(0, 0,  CGRectGetWidth( _cellFrame.imagesFrame),CGRectGetHeight( _cellFrame.imagesFrame));
        [_images addSubview:imageView];
    }
    if (count>1) {
        int i=0;
        for (Image *image in _imagesArr) {
            if (i==9) {
                break;
            }
            UIImageView *imageView = _imageViews[i];
            imageView.frame = CGRectMake(i%3*_cellFrame.imageSize, i/3*_cellFrame.imageSize, _cellFrame.imageSize-2, _cellFrame.imageSize-2);
            imageView.layer.masksToBounds = YES;
            imageView.contentMode = UIViewContentModeScaleAspectFill;
            [_images addSubview:imageView];
            imageView.image = [UIImage imageNamed:image.imageURL];
            i++;
        }
    }
}
@end

还有个类没贴出来,其实就是个model类,我自己编的数据,不看也罢。

这种方法其实是最简单无脑的,根据数据源和布局方式计算高度,简单粗暴,而且好控制,适合新手,就是代码写得多,布局简单点的还好,复杂点的估计会崩溃😂

能看到这里的是真爱!

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

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • Swift版本点击这里欢迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh阅读 25,256评论 7 249
  • 愿我出走半生,归来仍是少年。 时间过得很快,转眼我们就长大成人了。时间带给了我们成长,我们却给了我们自己一个又一个...
    战长歌阅读 193评论 0 0
  • 穿雨凉亭歇 从心听遍 已满目疮痍 楼台的天空 像蜘蛛的网格 寥寥点点的星光 来往屑屑的云 莫名折胶的风 忽然 前方...
    牛奶噜噜的石头阅读 240评论 0 1
  • 钓鲤鱼要选择的钓点,这些地方鲤鱼更多哦! 1:两个较大水面相连部位的狭窄处的两侧,是垂钓鲤鱼的好钓位这是根据鲤鱼喜...
    钓侠阅读 390评论 0 2