UITableView在IOS开发中占据非常重要的位置,必须熟练掌握。
学习UITableView之前,先了解一下一些基本概念:
从上面可以了解到,section和row代表一个UITableViewCell在UITableView上的位置
下面,我们创建一个UITableView:
//style是一个UITableViewStyle类型的参数,是一个枚举类型,包含UITableViewStylePlain,UITableViewStyleGrouped
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain]; [self.view addSubview:tableView];
下面是UITableView的常用属性:
rowHeight | 行高 |
separatorStyle | 分隔线样式 |
separatorColor | 分隔线颜色 |
tableHeaderView | UITableView的置顶视图 |
tableFooterView | UITableView置底视图 |
UITableView基础
UITableView中有两个重要的属性:dataSource(遵循UITableViewDataSource协议)和delegate(遵循UITableViewDelegate协议)
其中dataSource是和显示数据相关的代理,delegate是和视图操作相关的代理
UITableViewDataSource协议中有两个必须实现的协议方法:
- ( NSInteger )tableView:( UITableView *)tableView numberOfRowsInSection:( NSInteger )section; | UITableView每个分区包含的行数 |
- ( UITableViewCell *)tableView:( UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath; | 每一行要显示的Cell |
第一个方法可以根据给出的参数section不同返回不同的行数
第二个方法:tableView每次要显示一个Cell都会调用这个方法获取
UITableView的每一个单元格是UITableViewCell类的对象,默认提供了三个视图属性:
下面是返回Cell的例子:(没有使用registerClass注册的情况)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellID = @"cell"; //通过标识符,在tableView的重用池中找到可用的Cell(在重用池内部其实是一个可变的集合) UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; //如果重用池中没有这个标识符对应的cell,则创建一个新的,并且设置标识符 if (!cell) { //代码块内只做Cell样式的处理,不做数据设置 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:cellID]; } //对Cell做数据设置 [cell.textLabel setText:@"标题"]; [cell.detailTextLabel setText:@"描述:这是小标题"]; return cell; }
UITableView有一个重用池机制管理Cell,目的是使用尽可能少的Cell显示所有的数据
UITableView重用Cell的流程
在创建UITableView之后,需要注册一个Cell类,当重用池中没有Cell的时候,系统可以自动创建Cell。相关方法:
[tableView registerClass:( Class)cellClass forCellReuseIdentifier:( NSString *)identifier];(可以使用不同identifier进行多次注册)
系统提供了一个获取重用池中Cell的方法(需要一个重用标识):
- ( UITableViewCell *)dequeueReusableCellWithIdentifier:( NSString *)identifier;
UITableView的常用协议方法
- ( NSInteger )numberOfSectionsInTableView:( UITableView *)tableView | UITableView分区个数 |
- ( NSString *)tableView:( UITableView *)tableView titleForHeaderInSection:( NSInteger )section | 分区的顶部标题 |
- ( NSString *)tableView:( UITableView *)tableView titleForFooterInSection:( NSInteger )section | 分区的底部标题 |
- ( NSArray *)sectionIndexTitlesForTableView:( UITableView *)tableView | UITableView右侧的索引录 |
- ( void )tableView:( UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath | 告诉delegate选中了一个Cell |
- ( CGFloat )tableView:( UITableView *)tableView heightForRowAtIndexPath:( NSIndexPath *)indexPath | 每一行的高度 |
- ( CGFloat )tableView:( UITableView *)tableView heightForHeaderInSection:( NSInteger )section | 每一个分区的顶部高度 |
- ( UIView *)tableView:( UITableView *)tableView viewForHeaderInSection:( NSInteger )section | 每一个分区的顶部自定义视图 |
UITableView编辑
流程:
//重写UITableViewDataSource的协议方法,根据indexPath决定哪些Cell处于编辑状态,返回YES是可编辑,NO为不可编辑 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
//重写UITableViewDelegate的协议方法,根据indexPath可以决定Cell的编辑样式,是添加UITableViewCellEditingStyleInsert还是删除UITableViewCellEditingStyleDelete,还是不进行编辑UITableViewCellEditingStyleNone - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
//重写UITableViewDataSource协议方法,根据editingStyle删除indexPath位置的Cell,还是在indexPath处插入Cell,修改数据源 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
注意:编辑结束后,由于numberOfRowInSection这个协议方法只在tableView添加到父视图的时候调用一次,而且table上的数据都是由数组提供,因此,需要先改变数组中的数据,然后让table的协议重新调用进行重新赋值
即先修改数据源,在刷新table(使用[table reloadData]方法刷新)
UITableView移动
//返回YES允许移动 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
//修改数据源,再进行[tableView reloadData]更新tableView视图数据 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
UITableViewCell
1.自定义Cell
一般而言,Cell在创建的时候的frame大小是(0,0,320,44),而我们设定的Cell的高度一般会大于44。因此:在自定义Cell中创建子视图的frame为CGRectZero。在Cell添加到tableView上的时候才给子视图设置frame,Cell添加到tableView的时候大小已经更改为tableView设定的大小,所以在自定义Cell的方法layoutSubviews中设置子视图的frame
2.Model的使用
Model类的作用主要是为我们提供数据,一般我们的数据都是存放在数组和字典中,OC中的KVC就是帮助我们将字典转换为Model类而存在的
使用步骤:
注意:Model类要重写 -( void )setValue:( id )value forUndefinedKey:( NSString *)key,防止找不到和key值相同的属性时,会crash,当key值为系统关键字,可以在方法里面为对应的属性(属性名和系统关键字不冲突)赋值,比如_id = value;
3.多种Cell混合使用
不同的Cell需要使用不同的重用标识符来进行区分,而重用标识符的区分需要根据不同的情况来区分,比如:
4.自适应高度
//获得字体样式属性 NSDictionary *att = @{NSFontAttributeName:[UIFont systemFontOfSize:18.0]}; //根据字体样式属性获得高度 CGRect rect = [string boundingRectWithSize:CGSizeMake(300,MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:att context:nil]; //重新设置显示文本控件的frame [self.label setFrame:CGRectMake(0,0,300,rect.size.height)]; //我们可以定义一个类专门用来计算文本高度,这样可以使用时直接调用
通过协议方法- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath设定Cell的高度 在自定义Cell中的layoutSubviews方法中设定子视图的高度
转载请注明:作者SmithJackyson