您好,欢迎来到知库网。
搜索
您的当前位置:首页关于Cell高度自适应的解决方案(非三方库)

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

来源:知库网

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

以我们公司项目为例,是一个社区的时间线的需求,类似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类,我自己编的数据,不看也罢。

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

能看到这里的是真爱!

Copyright © 2019- zicool.com 版权所有 湘ICP备2023022495号-2

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务