Cell的复用及自定义Cell
Cell的复用及自定义Cell
- 前言
- Cell的复用
- 非注册方法(手动)
- 注册方法(自动)
- 自定义Cell
前言
在iOS开发中,UITableView
和 UICollectionView
是常用的列表视图控件,而 Cell复用 和 自定义Cell 是优化其性能和灵活性的关键技术。
Cell的复用
当 UITableView
或 UICollectionView
显示大量数据时,系统不会为每个数据项都创建一个新的 Cell
,系统会维护一个可重用的Cell
队列,当Cell
滚出屏幕时会被放入队列,而当需要显示新的Cell时,系统会优先从队列中取出可重用的Cell进行配置,即 复用已经滚出屏幕的Cell,以减少内存占用和提升性能。
实现Cell的复用有两种方法:
- 非注册方法(即手动判空)
- 注册方法(即使用Cell的自动注册机制)
非注册方法(手动)
手动复用Cell的方法步骤:
- 注册Cell类(即在设置复用标识符):创建一个局部字符串变量作为Cell的类型。在创建Cell时,将这个标识符作为参数传入
- 复用Cell:通过调用
UITableView
或UICollectionView
的dequeueReusableCell(withIdentifier:)方法来请求一个已经不显示在屏幕但是没有被销毁的Cell来显示新的Cell - 配置Cell:重新配置复用的Cell以显示新的数据
代码演示:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {static NSString *strID = @"id";UITableViewCell *cell = [_tabView dequeueReusableCellWithIdentifier: strID];if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: strID];}cell.textLabel.text = @"aaa";return cell;
}
注册方法(自动)
与手动复用Cell的区别在于不用手动判空。
自动复用Cell的方法步骤:
- 注册Cell类型:创建一个局部字符串变量作为Cell的类型。在创建Cell时,将这个标识符作为参数传入
- 请求复用的Cell:使用dequeueReusableCell(WithIdentifier:)获取可复用的cell
- 创建新的Cell:不用判空,如果dequeueReusableCell(WithIdentifier:)方法返回nil,自动创建一个新的Cell并返回
- 配置Cell:重新配置复用的Cell以显示新的数据
代码演示:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {static NSString *strID = @"id";MyTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier: strID];cell.backgroundColor = [UIColor redColor];return cell;
}
自定义Cell
默认的 UITableViewCell
或 UICollectionViewCell
样式有限,通常需要 自定义Cell 来满足UI需求。
自定义Cell的方法步骤:
- 初始化阶段:
- ViewController加载时创建并配置UITableView
- 注册自定义Cell类与复用标识的关联
- Cell创建阶段:
- 当tableView需要显示cell时,调用
cellForRowAtIndexPath:
- 系统首先尝试从复用队列中获取cell
- 如果没有可复用的cell,系统会调用
initWithStyle:reuseIdentifier:
初始化新的cell - 在初始化方法中创建并配置label1和label2
- 当tableView需要显示cell时,调用
- 布局阶段:
- 当cell需要显示时,系统调用
layoutSubviews
- 在layoutSubviews中设置两个label的精确位置
- 当cell需要显示时,系统调用
- 复用阶段:
- 当cell滚出屏幕时,会被放入复用队列
- 当新的cell需要显示时,优先从复用队列中获取
代码演示:
UICellTableViewCell.h
定义一个继承UITableViewCell的Cell类
#import <UIKit/UIKit.h>@interface UICellTableViewCell : UITableViewCell
@property(nonatomic, strong) UILabel *label1;
@property(nonatomic, strong) UILabel *label2;
@end
UICellTableViewCell.m
初始化方法和布局方法
#import "UICellTableViewCell.h"@implementation UICellTableViewCell-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];if ([reuseIdentifier isEqual:@"cell"]) {_label1 = [[UILabel alloc] init];_label1.textColor = [UIColor greenColor];_label1.font = [UIFont systemFontOfSize:20];[self.contentView addSubview:_label1];_label2 = [[UILabel alloc] init];_label2.textColor = [UIColor cyanColor];_label2.font = [UIFont systemFontOfSize:15];[self.contentView addSubview:_label2];}return self;
}-(void)layoutSubviews {_label1.frame = CGRectMake(100, 20, self.contentView.bounds.size.width - 40, 20);_label2.frame = CGRectMake(100, 40, self.contentView.bounds.size.width - 40, 20);
}
注册自定义Cell类,将tableView添加到视图
//ViewController.h
#import <UIKit/UIKit.h>@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {UITableView *_tableView;
}@end
//ViewController.m
#import "ViewController.h"
#import "UICellTableViewCell.h"
@interface ViewController ()@end
@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];_tableView.delegate = self;_tableView.dataSource = self;[_tableView registerClass:[UICellTableViewCell class] forCellReuseIdentifier:@"cell"];[self.view addSubview:_tableView];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {return 15;;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {UICellTableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:@"cell"];cell.label1.text = @"一级标题";cell.label2.text = @"二级标题";return cell;
}
@end
注意:所有子视图都应该添加到contentView上,而不是直接添加到cell本身。