使用纯代码的方式自定义等高cell的两种方式(Frame,Autolayout)
已经在我的这两篇博客中介绍:
UI 一一 自定义等高cell (纯代码-Frame)方式 和 UI 一一 自定义等高cell (纯代码-Autolayout)方式接下来继续搞自定义等高cell,通过xib的方式,再后来就是使用storyboard的方式了.是不是感觉好多.
其实并不多.实际开发中掌握一种适合自己的就行.因为这些方式的思路和代码几乎相同!
效果图都是一样的:
实现思路及简要过程:
新建一个继承自UITableViewCell
的子类,比如ZYTgCell
@interface ZYTgCell : UITableViewCell
@end
新建一个xib文件(文件名最好跟类名一致,比如ZYTgCell.xib)
- 修改cell的class为ZYTgCell
- 绑定循环利用标识
- 添加子控件,设置子控件约束
- 将子控件连线到类扩展中
@interface ZYTgCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
@end
在ZYTgCell.h文件中提供一个模型属性,比如ZYTg模型
@class ZYTg;
@interface ZYTgCell : UITableViewCell
/** 团购模型数据 */
@property (nonatomic, strong) ZYTg *tg;
@end
在ZYTgCell.m中重写模型属性的set方法
- 在set方法中给子控件设置模型数据
- (void)setTg:(ZYTg *)tg
{
_tg = tg;
// .......
}
在控制器中
- 注册xib文件
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ZYTgCell class]) bundle:nil] forCellReuseIdentifier:ID];
- 给cell传递模型数据
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 访问缓存池
ZYTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 设置数据(传递模型数据)
cell.tg = self.tgs[indexPath.row];
return cell;
}
这里有些注意点:
1. 我们之前使用纯代码方式来自定义cell的时候,注册文件使用的是这个方法:
[self.tableView registerClass:[ZYTgCell class] forCellReuseIdentifier:ID];
使用xib创建cell的时候使用的是这个方法:
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ZYTgCell class]) bundle:nil] forCellReuseIdentifier:ID];
为什么不可以使用上面的注册方法呢?
因为使用上面的那个注册方法,当缓存池中没有可用的cell的时候,就会自己去创建cell,创建cell的时候,就会调用调用initWithStyle这个方法,
这个方法是用来创建子控件,并设置子控件的一些初始化值.而我们是通过创建xib文件的方法创建子控件,所以根本不会使用到这个方法.
所以我们要使用下面的方法来注册,实现优化cell.
2. 在xib文件中,一般在identifier中绑定重用标识.
具体实现代码如下:
ZYTg 文件
// 注意: ZYTg模型中,不需要再把字典中的数据,传到这个数据模型中,
因为我们使用了第三方框架MJExtension,这个框架中有需要快速转成模型的方法.使用这个框架会方便很多.
它会自动加载plist中的数据,并赋值给数据模型.
@interface ZYTg : NSObject
/** 图标 */
@property (nonatomic, copy) NSString *icon;
/** 标题 */
@property (nonatomic, copy) NSString *title;
/** 价格 */
@property (nonatomic, copy) NSString *price;
/** 购买数 */
@property (nonatomic, copy) NSString *buyCount;
@end
@implementation ZYTg
@end
ZYTgCell.xib文件
ZYTgCell文件
#import
@class ZYTg;
@interface ZYTgCell : UITableViewCell
/** ZYTg模型 */
@property(nonatomic,strong)ZYTg * tg;
@end
#import "ZYTg.h"
@interface ZYTgCell ()
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
@end
@implementation ZYTgCell
// 重写set方法,设置数据
- (void)setTg:(ZYTg *)tg
{
_tg = tg;
self.iconImageView.image = [UIImage imageNamed:tg.icon];
self.titleLabel.text = tg.title;
self.priceLabel.text = [NSString stringWithFormat:@"¥%@",tg.price];
self.buyCountLabel.text = [NSString stringWithFormat:@"%@人已购买",tg.buyCount];
}
@end
ViewController 文件
#import "ViewController.h"
#import "ZYTgCell.h"
#import "ZYTg.h"
#import "MJExtension.h"
@interface ViewController ()
/** 所有的团购数据 */
@property (nonatomic, strong) NSArray *tgs;
@end
@implementation ViewController
// 使用第三方框架加载plist数据
- (NSArray *)tgs
{
if (_tgs == nil) {
_tgs = [ZYTg mj_objectArrayWithFilename:@"tgs.plist"];
}
return _tgs;
}
NSString *ID = @"tg";
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 80;
//这种方法不会实现优化,因为最终转换为initWithStyle,通过xib的方式创建cell,不会调用initWithStyle方法
// [self.tableView registerClass: [ZYTgCell class]forCellReuseIdentifier:ID];
// 注册的方法(优化)
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ZYTgCell class]) bundle:nil] forCellReuseIdentifier:ID];
}
// 隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
return YES;
}
#pragma -mark 数据源方法
/** 有多少行数据 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tgs.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 创建一个重用标识
// 访问缓存池
// static NSString *ID = @"tg";
ZYTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 判断缓存池中是否空的,如果为空就创建
// if (cell == nil) {
// // 在xib中的identifier中设置标识为tg,就可以在缓存池中取到重用的cell
// cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([ZYTgCell class]) owner:nil options:nil] lastObject];
// }
// 设置数据(传递数据模型)
cell.tg = self.tgs[indexPath.row];
return cell;
}
@end
比如又有一个需求:
不同类型的cell共存.也就是说在一个UITableView中显示不同类型的cell.
要实现这种需求:
1. 就需要再创建一个继承UITableViewCell的子类,比如叫ZYTestCell
2. 再创建一个xib文件,并设置class为ZYTestCell.
3. 设置标识
4. 在控制器的方法中来根据indexPath.row 行号来使用这个cell.
这样就实现了等高且不同类型的cell同时出现在UITableView中.其实这种需求也是有的.
比如你在手机上看网易新闻的时候,突然加载一段广告,这个广告也在UITableView上显示,其实就是一个不同类型的cell.
具体代码(我把上面的代码稍作修改)
ViewController 文件
#import "ViewController.h"
#import "ZYTgCell.h"
#import "ZYTg.h"
#import "MJExtension.h"
#import "ZYTestCell.h"
@interface ViewController ()
/** 所有的团购数据 */
@property (nonatomic, strong) NSArray *tgs;
@end
@implementation ViewController
// 使用第三方框架加载plist数据
- (NSArray *)tgs
{
if (_tgs == nil) {
_tgs = [ZYTg mj_objectArrayWithFilename:@"tgs.plist"];
}
return _tgs;
}
NSString *tgID = @"IDtg";
NSString *testID = @"testTg";
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.rowHeight = 80;
//这种方法不会实现优化,因为最终转换为initWithStyle,通过xib的方式创建cell,不会调用initWithStyle方法
// [self.tableView registerClass: [ZYTgCell class]forCellReuseIdentifier:ID];
// 注册的方法(优化)
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ZYTgCell class]) bundle:nil] forCellReuseIdentifier:tgID];
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([ZYTestCell class]) bundle:nil] forCellReuseIdentifier:testID];
}
// 隐藏状态栏
- (BOOL)prefersStatusBarHidden
{
return YES;
}
#pragma -mark 数据源方法
/** 有多少行数据 */
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.tgs.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 奇数cell显示TgCell,偶数行cell显示TestCell
if (indexPath.row % 2 == 0) {
ZYTgCell *cell = [tableView dequeueReusableCellWithIdentifier:tgID];
cell.tg = self.tgs[indexPath.row];
return cell;
}else{
ZYTestCell *cell = [tableView dequeueReusableCellWithIdentifier:testID];
return cell;
}
}
@end
效果如下图: