一.UITableView的重要性
-
产品上讲:
App靠内容黏住用户,没有内容的App,注定是没有生命力的。 而UITableView,便是用于海量数据的展示,我们平时使用的软件中到处都可以看到它的影子,类似于微信、QQ、新浪微博等软件基本上随处都是UITableView -
技术上讲:
UITableView具有重用和延迟加载等特性, 只要正确使用,海量的数据便可在这张表上,一览无余;
我们可以借鉴苹果设计UITableView的思想来自定义控件(这点很重要)
二.UITableView的结构
-
tableView的大致结构
结构.png -
tableViewCell
cell苹果提供了四种类型
本例的示意图是用xib自定义的cell
accessory viewaccessory view苹果也提供了几种类型
Snip20160511_13.png
Paste_Image.png
三.本人项目中常用的方法(比较乱,请谅解)
1.两种初始化的方式
UITableViewStylePlain,UITableViewStyleGrouped
看看官方文档的解释:
UITableViewStylePlain.png UITableViewStyleGrouped.png
- 区别一:(翻译一下子)
UITableViewStylePlain形式的tableView section的headerView和footerView会浮动
UITableViewStyleGrouped形式的tableView则不会 - 区别二:这个文字不好描述,还是直接上图吧
UITableViewStyleGrouped形式的tableView,若要修改section之间的距离,需要实现以下四个代理方法:
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
}
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
}
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
}
2.闭合cell的分割线(相信有很多开发者碰到这样的需求,默认的分割线左边是没有闭合的)
实现以下代理:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]) {
[cell setPreservesSuperviewLayoutMargins:NO];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
}
3.取消cell的分割线
- 第一种方式
设置tableView的separatorStyle 为UITableViewCellSeparatorStyleNone
苹果提供了如下枚举
typedef NS_ENUM(NSInteger, UITableViewCellSeparatorStyle) {
UITableViewCellSeparatorStyleNone,
UITableViewCellSeparatorStyleSingleLine,
UITableViewCellSeparatorStyleSingleLineEtched // This separator style is only supported for grouped style table views currently
} __TVOS_PROHIBITED;
第三个说是只在grouped style table views才可以用但是和UITableViewCellSeparatorStyleNone的效果是一样的,不知道是不是bug(应该是我太菜,没理解)
- 第二种方式
这种方式的好处在于只让某个cell的分割线取消时,比较好处理
[cell setSeparatorInset:UIEdgeInsetsMake(0, 0, 0, 1000000)];
4.关于自定义cell
- 第一种方式:xib拖
- 第二种方式:纯代码
// xib方式的注册
[_tableView registerNib:[UINib nibWithNibName:@"" bundle:nil] forCellReuseIdentifier:@""];
// 纯代码方式的注册
[_tableView registerClass:[Cell class] forCellReuseIdentifier:@""];
注意:纯代码的cell布局尽量在这里处理
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
[self layoutCellUI];
}
return self;
}
5.cell的selectionStyle
首先看下官方提供的几种:
typedef NS_ENUM(NSInteger, UITableViewCellSelectionStyle) {
UITableViewCellSelectionStyleNone,
UITableViewCellSelectionStyleBlue,
UITableViewCellSelectionStyleGray,
UITableViewCellSelectionStyleDefault NS_ENUM_AVAILABLE_IOS(7_0)
};
如果我们要自定义选中状态呢?
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
if (selected) {
self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"xozaa_discover_activity"]];
self.lblText.textColor = [UIColor whiteColor];
} else {
self.selectedBackgroundView = nil;
self.lblText.textColor = [UIColor blackColor];
}
}
效果如下:
效果图
这里需要注意的就是cell里其他控件的状态改变是否要变化
6.取消选中状态
[tableView deselectRowAtIndexPath:indexPath animated:YES];
如果有这样的需求:跳转到另一个页面再回到本页面,要告诉用户我刚才点了哪个cell,那么我们可以这样处理:
(void) viewWillAppear: (BOOL)inAnimated {
NSIndexPath *selectedIndexPath = [self.table indexpathForSelectedRow];
if(selectedIndexPath) {
[self.table deselectRowAtIndexpath:selectedIndexPath animated:NO];
}
}
7.cell的赋值
tableView的数据处理应该大部分都用数组处理吧,假设以数组处理,如下
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TestTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"TestTableViewCell"];
NSDictionary* dic = _arr[indexPath.row];
[cell fillData:dic];
return cell;
}
这里要说的是给cell填充数据时,我们尽量不要在ViewController里边写,展示的事情应该交给View层去处理,ViewController只是把Model的数据发送过去。
之前见过实现这个代理时写的超长的方法,所有的业务逻辑,展示逻辑都在这里,看这种代码的时候真的很痛苦
减轻ViewController的压力,维护起来也很方便
8.左滑cell处理
实现如下代理,注意这个代理仅支持iOS8以后的系统
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;
效果图:
效果图.png直接上代码
#pragma mark - UITableViewDelegate
/**
* 左滑事件
*
* @param tableView
* @param indexPath
*
* @return 数组
*/
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
// 删除按钮
UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
NSLog(@"删除");
// 注意数据源对应删除,否则会报Assertion failure in -[UITableView _endCellAnimationsWithContext:] 这样的错误
// 如果一个分组中,有多条数据时,你删除其中一条,正确;当一个分组中,你要删除唯一的一条时,仍然会报出如上的错误!,测试需要删除这个section
if (indexPath.section == 1) {
[arr2 removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}];
// 置顶按钮
UITableViewRowAction *toTopRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"置顶" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
NSLog(@"置顶");
// 注意数据源对应处理
[tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
}];
// 设置按钮的背景色
toTopRowAction.backgroundColor = [UIColor orangeColor];
// 其他按钮
UITableViewRowAction *otherRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"其他" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath){
NSLog(@"其他");
}];
// 设置按钮的背景色
otherRowAction.backgroundColor = [UIColor cyanColor];
//返回按钮数组
return @[deleteRowAction, toTopRowAction, otherRowAction];
}
9.各种reload
假设我们的tableView初始化已经完毕
@property (nonatomic,strong) UITableView *tableView;
// 刷新整个表
[self.tableView reloadData];
// 某个section的刷新
NSIndexSet *indexSet=[[NSIndexSet alloc]initWithIndex:2];
[self.tableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];
// 某个cell的刷新
NSIndexPath *indexPath=[NSIndexPath indexPathForRow:3 inSection:0];
[self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
10 UITableView初级优化
如果我们的cell高度是固定的,那么我强烈建议定义cell高度的地方放到初始化的时候
而不要去走代理方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 100.0;
}
很多人都把优化的重点放到了 cell for row at indexpath 那个方法里了,在这里尽可能的少计算,但是却忽略了另一个很轻松就能提升加载时间的方法 :
eg:_tableView.rowHeight = 100.0;
Table View 在每次 reload data 时都会要所有 cell 的高度!这就是说你有一百行 cell,就x向代理要100次每个cell 的高度,而不是当前屏幕显示的cell 的数量的高度!减少 计算高度时的时间,对于提升加载 Table View 的速度有非常明显的提高!
暂时先写这么多吧,其实还有很多小细节没提及到(tableView的刷新,section的刷新,cell的刷新,cell的添加、删除,表格右边建立一个浮动的索引,控制该表格滚动到指定indexPath等等)这篇是比较基础的东东,但还是希望会给大家带来帮助 O(∩_∩)O
网友评论
谢谢你