1、自定义非等高 Cell介绍

  • 1.1 代码自定义(frame)

    • 新建一个继承自 UITableViewCell 的类。
    • 重写 initWithStyle:reuseIdentifier: 方法。
      • 添加所有需要显示的子控件(不需要设置子控件的数据和 frame, 子控件要添加到 contentView 中)。
      • 进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)。
    • 提供 2 个模型。
      • 数据模型: 存放文字数据\图片数据。
      • frame 模型: 存放数据模型\所有子控件的 frame\cell 的高度。
    • cell 拥有一个 frame 模型(不要直接拥有数据模型)。
    • 重写 cell frame 模型属性的 setter 方法: 在这个方法中设置子控件的显示数据和 frame。
    • frame 模型数据的初始化已经采取懒加载的方式(每一个 cell 对应的 frame 模型数据只加载一次)。
  • 1.2 代码自定义(Autolayout)

    • 新建一个继承自 UITableViewCell 的类。
    • 重写 initWithStyle:reuseIdentifier: 方法。
      • 添加所有需要显示的子控件(不需要设置子控件的数据和 frame, 子控件要添加到 contentView 中)。
      • 进行子控件一次性的属性设置(有些属性只需要设置一次, 比如字体\固定的图片)。
    • 设置 cell 上子控件的约束。
    • 在模型中增加一个 cellHeight 属性,用来存放对应 cell 的高度。
    • 在 cell 的模型属性 set 方法中调用 [self layoutIfNeed] 方法强制布局,然后计算出模型的 cellheight 属性值。
    • 在控制器中实现 tableView:estimatedHeightForRowAtIndexPath: 方法,返回一个估计高度,比如 200。
    • 在控制器中实现 tableView:heightForRowAtIndexPath: 方法,返回 cell 的真实高度(模型中的 cellHeight 属性)。

2、代码

  • 2.1 XMGStatus.h

@interface XMGStatus : NSObject

@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *text;
@property (strong, nonatomic) NSString *icon;
@property (strong, nonatomic) NSString *picture;
@property (assign, nonatomic, getter=isVip) BOOL vip; /** cell 的高度 */
@property (assign, nonatomic) CGFloat cellHeight; + (instancetype)statusWithDict:(NSDictionary *)dict; @end
  • 2.2 XMGStatus.m

@implementation XMGStatus

+ (instancetype)statusWithDict:(NSDictionary *)dict {

	XMGStatus *status = [[self alloc] init];
[status setValuesForKeysWithDictionary:dict];
return status;
} @end
  • 2.3 XMGStatusCell.h

@class XMGStatus;

@interface XMGStatusCell : UITableViewCell

+ (instancetype)cellWithTableView:(UITableView *)tableView;

/** 模型数据 */
@property (nonatomic, strong) XMGStatus *status; @end
  • 2.4 XMGStatusCell.m

#define MAS_SHORTHAND
#define MAS_SHORTHAND_GLOBALS #import "Masonry.h" @interface XMGStatusCell() @property (weak, nonatomic) UIImageView *iconView;
@property (weak, nonatomic) UILabel *nameLabel;
@property (weak, nonatomic) UIImageView *vipView;
@property (weak, nonatomic) UILabel *contentLabel;
@property (weak, nonatomic) UIImageView *pictureView; @end @implementation XMGStatusCell + (instancetype)cellWithTableView:(UITableView *)tableView { static NSString *ID = @"status";
XMGStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (cell == nil) {
cell = [[XMGStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID];
}
return cell;
} - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { UIImageView *iconView = [[UIImageView alloc] init];
[self.contentView addSubview:iconView];
self.iconView = iconView; UILabel *nameLabel = [[UILabel alloc] init];
[self.contentView addSubview:nameLabel];
self.nameLabel = nameLabel; UIImageView *vipView = [[UIImageView alloc] init];
[self.contentView addSubview:vipView];
self.vipView = vipView; UILabel *contentLabel = [[UILabel alloc] init];
contentLabel.numberOfLines = 0; // 设置 label 每一行文字的最大宽度
contentLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20; [self.contentView addSubview:contentLabel];
self.contentLabel = contentLabel; UIImageView *pictureView = [[UIImageView alloc] init];
[self.contentView addSubview:pictureView];
self.pictureView = pictureView;
}
return self;
} - (void)layoutSubviews { [super layoutSubviews];
CGFloat margin = 10; [self.iconView makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(30);
make.left.top.offset(margin);
}]; [self.nameLabel makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.iconView);
make.left.equalTo(self.iconView.right).offset(margin);
}]; [self.vipView makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(14);
make.left.equalTo(self.nameLabel.right).offset(margin);
make.centerY.equalTo(self.nameLabel.centerY);
}]; [self.contentLabel makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.iconView.bottom).offset(margin);
make.left.offset(margin);
// make.right.offset(-margin); // 可加可不加
}]; [self.pictureView makeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(100);
make.top.equalTo(self.contentLabel.bottom).offset(margin);
make.left.offset(margin);
}];
} - (void)setStatus:(XMGStatus *)status {
_status = status; // 设置显示的数据 self.iconView.image = [UIImage imageNamed:status.icon];
self.nameLabel.text = status.name; if (status.isVip) {
self.nameLabel.textColor = [UIColor orangeColor];
self.vipView.hidden = NO;
} else {
self.nameLabel.textColor = [UIColor blackColor];
self.vipView.hidden = YES;
} self.contentLabel.text = status.text; if (status.picture) {
self.pictureView.hidden = NO;
self.pictureView.image = [UIImage imageNamed:status.picture];
} else {
self.pictureView.hidden = YES;
} // 计算 cell 高度 // 强制布局
[self layoutIfNeeded]; // 计算 cell 的高度
if (self.pictureView.hidden) { // 没有配图
_status.cellHeight = CGRectGetMaxY(self.contentLabel.frame) + 10;
} else { // 有配图
_status.cellHeight = CGRectGetMaxY(self.pictureView.frame) + 10;
}
} @end
  • 2.5 XMGStatusesViewController.m

@interface XMGStatusesViewController ()

@property (strong, nonatomic) NSArray *statuses;

@end

@implementation XMGStatusesViewController

- (NSArray *)statuses {

	if (_statuses == nil) {

		// 加载plist中的字典数组
NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
NSArray *dictArray = [NSArray arrayWithContentsOfFile:path]; // 字典数组 -> 模型数组
NSMutableArray *statusArray = [NSMutableArray array];
for (NSDictionary *dict in dictArray) {
XMGStatus *status = [XMGStatus statusWithDict:dict];
[statusArray addObject:status];
}
_statuses = statusArray;
}
return _statuses;
} #pragma mark - Table view data source - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.statuses.count;
} - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { XMGStatusCell *cell = [XMGStatusCell cellWithTableView:tableView];
cell.status = self.statuses[indexPath.row];
return cell;
} #pragma mark - 代理方法
// 返回每一行的高度
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { XMGStatus *staus = self.statuses[indexPath.row];
return staus.cellHeight;
} /**
* 返回每一行的估计高度
* 只要返回了估计高度,那么就会先调用 tableView:cellForRowAtIndexPath: 方法创建 cell,
* 再调用 tableView:heightForRowAtIndexPath: 方法获取 cell 的真实高度
*/
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { return 200;
} @end
  • 2.6 运行效果图

  • ---

3、其它设置方式

  • 3.1 计算方式

    • BookModel.h
    @property(nonatomic, copy)NSString *title;
    @property(nonatomic, copy)NSString *detail;
    @property(nonatomic, copy)NSString *icon;
    @property(nonatomic, copy)NSString *price;
    • BookCell.h
    @property(nonatomic, retain)UILabel *titleLabel;
    @property(nonatomic, retain)UILabel *detailLabel;
    @property(nonatomic, retain)UIImageView *iconView;
    @property(nonatomic, retain)UILabel *priceLabel;
    • 设置行高
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    	// 从数据源数组中取出数据
    BookModel *bookModel = [myDataArray objectAtIndex:indexPath.row]; // 计算 detailLabel 占用的高度
    CGFloat detialHeight = [bookModel.detail boundingRectWithSize:CGSizeMake(self.view.bounds.size.width - 40, CGFLOAT_MAX)
    options:NSStringDrawingUsesLineFragmentOrigin
    attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14]}
    context:nil].size.height; // 判断是否有图片
    if (bookModel.icon.length) { // 60 为图片的高度
    return 30 + detialHeight + 60 + 30;
    }
    else {
    return 30 + detialHeight + 30;
    }
    }
    • 设置每一行显示的内容
    // 设置每一行显示的内容
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { BookCell3 *cell = [tableView dequeueReusableCellWithIdentifier:@"test" forIndexPath:indexPath];
    BookModel *bookModel = [myDataArray objectAtIndex:indexPath.row]; // 设置 titleLabel
    cell.titleLabel.text = bookModel.title; // 设置 detailLabel // 计算 detailLabel 的高度
    CGSize detialSize = [bookModel.detail boundingRectWithSize:CGSizeMake(self.view.bounds.size.width - 40, CGFLOAT_MAX)
    options:NSStringDrawingUsesLineFragmentOrigin
    attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:14]}
    context:nil].size; CGRect detialFrame = cell.detailLabel.frame;
    detialFrame.size.height = detialSize.height + 5; // 加偏移量 5,适应标点无法换行
    detialFrame.size.width = detialSize.width + 5;
    cell.detailLabel.frame = detialFrame; // 设置 detailLabel 的 frame cell.detailLabel.text = bookModel.detail; // 判断是否有图片
    if (bookModel.icon.length) { // 设置 iconView CGRect iconFrame = cell.iconView.frame;
    iconFrame.origin.y = detialFrame.origin.y + detialFrame.size.height;
    cell.iconView.frame = iconFrame; cell.iconView.image = [UIImage imageNamed: bookModel.icon]; // 设置 priceLabel CGRect priceFrame = cell.priceLabel.frame;
    priceFrame.origin.y = iconFrame.origin.y + iconFrame.size.height;
    cell.priceLabel.frame = priceFrame; cell.priceLabel.text = bookModel.price;
    }
    else { // 设置 priceLabel CGRect priceFrame = cell.priceLabel.frame;
    priceFrame.origin.y = detialFrame.origin.y + detialFrame.size.height;
    cell.priceLabel.frame = priceFrame; cell.priceLabel.text = bookModel.price;
    }
    return cell;
    }
  • 3.2 系统自动布局方式

    • 自适应 cell 中较高的一个视图的高度。
    • ImageView 与 Label 同行显示,且都设置了上下边缘约束,ImageView 的图片填充模式为 Aspect Fit,否则图片将会被拉长。
    • 协议方法 方式设置
    // 动态设置行高
    - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { /*
    行高自适应 Label 高度
    */ secondTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"secondTableViewCell" forIndexPath:indexPath]; cell.secondLabel.text = [_labelArray objectAtIndex:indexPath.row]; return [cell.contentView systemLayoutSizeFittingSize:(UILayoutFittingCompressedSize)].height + 1;
    } // 属性变量 方式设置
    self.tableView.estimatedRowHeight = 80;
    self.tableView.rowHeight = UITableViewAutomaticDimension;
    ```![](https://images2018.cnblogs.com/blog/1213778/201808/1213778-20180804232655846-607601308.png)

自定义非等高 Cell的更多相关文章

  1. iOS边练边学--自定义非等高的cell

    一.使用xib或者storyboard自定义非等高的cell实现方式差不多,这里简单介绍一下通过xib文件实现的方法 <1.1>创建一个继承自UITableViewCell的子类,比如Ch ...

  2. 非等高cell实战(01)-- 实现微博页面

    非等高cell实战(01)-- 实现微博页面 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战来整合一下. 首先看一下效果图: 需求分析 此页面为非等 ...

  3. 非等高cell实战--实现微博页面

    代码地址如下:http://www.demodashi.com/demo/11639.html 前言 学习过UITableView.AutoLayout以及MVC的相关知识,接下来通过一个微博页面实战 ...

  4. 自定义不等高cell—storyBoard或xib自定义不等高cell

    1.iOS8之后利用storyBoard或者xib自定义不等高cell: 对比自定义等高cell,需要几个额外的步骤(iOS8开始才支持) 添加子控件和contentView(cell的content ...

  5. iOS开发——UI进阶篇(三)自定义不等高cell,如何拿到cell的行高,自动计算cell高度,(有配图,无配图)微博案例

    一.纯代码自定义不等高cell 废话不多说,直接来看下面这个例子先来看下微博的最终效果 首先创建一个继承UITableViewController的控制器@interface ViewControll ...

  6. iOS开发——UI进阶篇(二)自定义等高cell,xib自定义等高的cell,Autolayout布局子控件,团购案例

    一.纯代码自定义等高cell 首先创建一个继承UITableViewCell的类@interface XMGTgCell : UITableViewCell在该类中依次做一下操作1.添加子控件 - ( ...

  7. 不等高cell的tableView界面搭建

    一.搭建界面 1.界面分析 分析界面的层次结构,分析界面应该用什么控件来搭建 2.界面层次结构 分析之后,我们可以把这个界面分为四个模块(topView middleView commentView ...

  8. 【Android 应用开发】 自定义组件 宽高适配方法, 手势监听器操作组件, 回调接口维护策略, 绘制方法分析 -- 基于 WheelView 组件分析自定义组件

    博客地址 : http://blog.csdn.net/shulianghan/article/details/41520569 代码下载 : -- GitHub : https://github.c ...

  9. ios中自定义tableView,CollectionView的cell什么时候用nib加载,什么时候用标识重用

    做了一段时间的iOS,在菜鸟的路上还有很长的路要走,把遇到的问题记下来,好记性不如烂笔头. 在项目开发中大家经常会用到tableView和collectionView两个控件,然而在cell的自定义上 ...

随机推荐

  1. Azure上通过haproxy实现APP Gateway或WAF的http跳转https

    Azure上的APP Gateway是七层负载均衡服务,WAF是APP Gateway服务的扩展.在实现七层负载均衡的同时,增加了WAF的功能,可以对后台的HTTP服务进行保护. Azure WAF采 ...

  2. laravel 导出导入excel和csv文件的 使用

    在项目中用到的常用功能数据导入导出 在laravel有插件可以直接使用 方便快捷 学习源头: https://www.cnblogs.com/martianShu/p/5869270.html htt ...

  3. Hudson和Jenkins的关系

    Jenkins is an open source continuous integration tool written in Java. The project was forked from H ...

  4. linux yum 脚本实现

    yum 位于linux /usr/bin/yum yum命令是python脚本进行编写的(python 2.6) #!/usr/bin/python2.6 import sys try: import ...

  5. Python打造一个目录扫描工具

    目标:用Python3写一款小型的web目录扫描工具 功能:1.扫描指定站点 2.指定网站脚本类型来扫描 3.可控线程 4.可保存扫描结果 首先定义一个命令参数的函数 def parse_option ...

  6. Canopy聚类算法(经典,看图就明白)

    只有这个算法思想比较对,其他 的都没有一开始的remove: 原网址:http://www.shahuwang.com/?p=1021 Canopy Clustering 这个算法是2000年提出来的 ...

  7. spring与struts有什么区别?

    Struts只是一个MVC框架(Framework),用于快速开发Java Web应用.Struts实现的重点在C(Controller),包括ActionServlet/RequestProcess ...

  8. 用UltraISO把硬盘文件制作成ISO格式

    转自:https://wenku.baidu.com/view/0052c88dcc22bcd126ff0cbf.html 用UltraISO把硬盘文件制作成ISO格式方法: 制作硬盘ISO文件步骤一 ...

  9. Windows平台上通过git下载github的开源代码

    常见指令整理: (1)检查ssh密钥是否已经存在.GitBash. 查看是否已经有了ssh密钥:cd ~/.ssh.示例中说明已经存在密钥 (2)生成公钥和私钥 $ ssh-keygen -t rsa ...

  10. ActiveMQ (一) 介绍与安装

    ActiveMQ是消息中间件的一种 ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provide ...