如果问 iOS 中最重要的最常用的 UI 控件是什么,我觉得 UITableView 当之无愧!似乎所有常规 APP 都使用到了 UITableView。下面就讲一讲 UITableView 的常用知识和使用原理及性能优化!
效果分别如图:
UITableViewStylePlain:一种平铺的效果,并且分组组头默认有停靠效果;
说完了 UITableView 的简介,下面来说说他它是如何展示数据的。
UITableView 和数据源的关系如下
数据源方法的调用过程
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView; // Default is 1 if not implemented
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
UITableView 还有一些其他的数据源方法如下
- /**
- * 返回组头标题
- */
- - (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- /**
- * 返回尾标题
- */
- - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
- ···
最简单的返回 UITableViewCell 的方法如下
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- UITableViewCell *cell = [[UITableViewCell alloc] init];
- cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
- return cell;
- }
但是实际使用过程中这样是非常耗费性能的,因为当用户滑动 UITableView 的时候,上面方法会疯狂的调用,疯狂的创建 UITableViewCell。
苹果对这种情况做了一些性能优化,UITableViewCell 在每次创建的时候只会创建当前 UI 页面上可见的 Cell。当 Cell 滑动到屏幕外面,当前 Cell 会被放入到缓存池中,并且可以给 Cell 设置一个复用标识,当下次使用 Cell 的时候可以先到缓存池中查找,如果有对应复用标识的 Cell 就直接拿出来使用,并重新给内容赋值。
所以根据苹果复用 Cell 的思路我们在调用返回 cell 的方法思路应该如下:
所以上面方法从提高性能角度考虑,应该重新写为下面这样:
- /**
- * 什么时候调用:每当有一个cell进入视野范围的时候调用
- */
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- // 0.创建cell复用标识
- static NSString *reuseIdentifier = @"cell";
- // 1.根据复用标识在复用池中进行查找
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
- // 2.判断如果复用池cell为nil就根据复用标识自己创建
- if (cell == nil) {
- cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
- }
- // 3.拿到cell进行数据覆盖
- cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
- return cell;
- }
我们可以手动给 tableview 注册对应标识的 cell,保证从缓存池中能加载到对应标识的 cell。
通过代码注册
- // 注册cell
- static NSString *reuseIdentifier = @"cell";
- [tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:reuseIdentifier];
通过 Xib 注册
- // 注册cell
- static NSString *reuseIdentifier = @"cell"; // 标识可以在Xib中创建
- [tableview registerNib:[UINib nibWithNibName:@"对应的Xib名称" bundle:nil] forCellReuseIdentifier:reuseIdentifier];
在数据源方法中返回 cell
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- // 1.根据复用标识在复用池中进行查找
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
- // 2.拿到cell进行数据覆盖
- cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
- return cell;
- }
第三种方式是通过 UITableViewController 在 StoryBoard 中创建,见下面:5.UITableViewController
有了数据源方法,tableview 就可以正常展示数据。有了对应的代理方法就可以正常监听 tableview 的事件操作。
下面列举一些常用代理方法:
- /**
- 返回行高,可根据不同行返回不同高
- @param tableView tableview
- @param indexPath 位置
- @return 行高
- */
- - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
- /**
- 返回估计行高,此方法不进行真实计算,课改变Cell计算高度方法的调用顺序,
- @param tableView tableview
- @param indexPath 位置
- @return 行高
- */
- - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
- /**
- cell的点击事件处理
- @param tableView tableview
- @param indexPath 位置
- */
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- /**
- cell将要被选中 -- 先需取消选中某个cell才能正常选中新的cell
- */
- - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath;
- /**
- cell将要被取消选中
- */
- - (nullable NSIndexPath *)tableView:(UITableView *)tableView willDeselectRowAtIndexPath:(NSIndexPath *)indexPath
- ···
UITableViewController 继承自 UIViewController。可以方便创建有 tableview 的控制器
通过 StoryBoard 创建 Cell 更加方便
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- // 1.会默认去缓存池中进行查找,如果没有自动去StoryBaord中找
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
- // 2.拿到cell进行数据覆盖
- cell.textLabel.text = [NSString stringWithFormat:@"第 %zd 行",indexPath.row];
- return cell;
- }
小结
来源: http://www.cnblogs.com/xiaoyouPrince/p/6596032.html