作为在开发中最常用的一个控件,UITableView也是在整个UIKit中比较复杂的一个,我们需要记的东西也特别多.另外苹果官方为我们提供了UITableViewController这个类,但是在这里我们不使用它.而是在UIViewController上面添加一个UITableView.
UITableView
UITableView继承于UIScrollView,当需要展示的数据量很多的时候,它是可以滚动显示的.
表视图的每一行都是由单元格(UITableViewCell)表示的.当我们要对数据分组显示时,苹果为我们提供了两种基本样式的显示,一种是分组样式,一种则为简单样式.
创建UITableView
我们初始化一个UITableView,并指定样式,然后进行其相关属性的设置,最后将他添加到控制器上.
// 1.创建tableView(表视图)并初始化,初始化的时候给一个样式
UITableView *tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped];
// 2.设置属性
// 设置分割线的颜色
tableView.separatorColor = [UIColor redColor];
// 设置分割线的风格
tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
// 设置行高
tableView.rowHeight = 100;
// 设置tableView的tableHeaderView
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 414, 200)];
headerView.backgroundColor = [UIColor cyanColor];
tableView.tableHeaderView = headerView;
// 设置tableView的tableFooterView(取消下面多余的线)
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 20)];
footerView.backgroundColor = [UIColor magentaColor];
tableView.tableFooterView = footerView;
// 设置索引条
tableView.sectionIndexColor = [UIColor blackColor];
// 背景颜色
tableView.sectionIndexBackgroundColor = [UIColor clearColor];
//
tableView.sectionIndexTrackingBackgroundColor = [UIColor lightGrayColor];
// 3.添加到视图
[self.view addSubview:tableView];
复制代码
在上面的代码中,我们对UITableView的分割线和行高,一起头尾视图,索引条这几个属性进行了相关设置,对于其他的属性,读者可以自己根据兴趣尝试设置.
关于UITableViewCell的相关
在UITableView中用于展示数据的主要就是UITableViewCell.在这里首相我想先说一下关于UITableViewCell的重用.
UITableViewCell的重用
如果我们想利用UITableView展示几条数据的话,我们可以依次创建这些数量的行来展示这些数据,但是我们如果有10000行甚至更多的数据要用来向用户展示呢?如果反复创建是十分消耗内存的.
这样我们就自然的想到,为什么要创建这么多次cell呢?我们为什么不将创建好的cell保存起来,放在一个队列中重用呢?这就是UITableViewCell的重用机制.当我们有10000条数据需要展示的时候,我们使用这个机制创建的行可能仅需要10个,这样就大大节约了内存.
UITableViewCell的创建
我们可以从官方的API中看到UITableViewCell的初始化方法.
![UITableViewCell的初始化方法]://upload-images.jianshu.io/upload_images/1230517-db6401da06482690.png)
在创建Cell的时候同样需要指定一个样式,并且设置一个标识.关于样式苹果给定了四个样式
读者可以一一试验,着这里就不做详细的讲解.
if (!cell) {
// 若重用池里面没有,则去创建identifier标识符的cell
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier];
}
复制代码
实际上,上述的创建UITableViewCell的方法是在iOS6之前的老方法.
在iOS6之后我们只需要注册在重用池中注册一下cell的重用标识符.在注册cell之前我们必须为cell设置重用标识符,这个标识符必须唯一.我们通常声明为静态字符串,我们不需要管理字符串的内存,也不需要对其进行释放.
// 声明重用标识符
static NSString *identifier = @"cellReuse";
复制代码
// 注册(iOS6 之后的写法)
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier];
复制代码
然后在UITableViewDataSource数据源方法中创建就可以了
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 先去重用池里面取带有identifier重用标识符的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
return cell;
}
复制代码
NSIndexPath
NSIndexPath代表UITableView的索引.由于我们创建的cell是重用的,这样一来我们便没法精确的确定这个行.出于此,系统为我们提供了一个标示行的类,就是NSIndexPath
NSIndexPath的常用属性有:
row表示分区中的行的索引,section标示分区的索引.通过这两个属性我们就可以找到想要的行.
关于自定义cell
关于UITableViewCell我们是可以根据自己的需要自定义的,我们只需要重新创建一个类继承自UITableViewCell,在其中设置成需要的样式.然后在注册和创建的时候使用自定义的cell就可以了,在这里我们假设我们创建一个MyTableViewCell,并且设置了重用标识符,那么注册和创建的方式如下.
注册
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:identifier];
复制代码
创建
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
复制代码
UITableViewDelegate和UITableViewDataSource
上面是对UITableView的整体结构介绍,如果我们要创建表视图展示数据,我们必须要为表视图设置代理和数据源,也就是UITableViewDelegate和UITableViewDataSource
先看数据源代理,数据源顾名思义,就是为表视图提供相关的数据.
我们看到API中有两个必须要实现的方法
//分区的个数,也就设置这个表分成几组(section)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//创建或者重用cell的代理方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码
另外我们可以对其每个分区的行数(row)进行设置,还可以设置其头尾(titleForHeaderInSection和titleForFooterInSection).
相对这些我跟想跟大家交流的是一些有趣的方法
编辑UITableView
使页面处于可编辑状态
// 第一步: 使页面处于可编辑状态
- (void)edit:(UINavigationController *)sender{
// 设置当前页面可以被编辑
// 当点击编辑的时候,页面应该处于可编辑状态,并且按钮文字变成"完成"
if ([sender.title isEqualToString:@"编辑"]) {
sender.title = @"完成";
[_tableView setEditing:YES animated:YES];
}else{
// 当点击完成时,应该让当前页面处于不可编辑状态,并且按钮文字显示为"编辑"
sender.title = @"编辑";
[_tableView setEditing:NO animated:YES];
}
}
复制代码
指定哪些行可以被编辑
// 指定哪些行可以被编辑
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 2) {
return NO;
}
return YES;
}
复制代码
根据路径指定编辑的样式
// 根据路径指定编辑的样式
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
if (indexPath.section == 5) {
return UITableViewCellEditingStyleInsert;
}
return UITableViewCellEditingStyleDelete;
}
复制代码
根据编辑风格完成编辑(先操作数据,在更新UI)
// 根据编辑风格完成编辑(先操作数据,在更新UI)
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
// 删除
if (editingStyle == UITableViewCellEditingStyleDelete) {
// 找到对应得分组
NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
// 当当前分组只有一个人的时候,删除元素之后,对应的分组也应该被删掉
if (array.count == 1) {
// 删除大字典里面的该分组
[_dataDictionary removeObjectForKey:_dataArray[indexPath.section]];
// 删除掉数组里面对应的key
[_dataArray removeObjectAtIndex:indexPath.section];
// 删除UI
NSIndexSet *set = [NSIndexSet indexSetWithIndex:indexPath.section];
[tableView deleteSections:set withRowAnimation:UITableViewRowAnimationFade];
}else{
// 删除数据
[array removeObjectAtIndex:indexPath.row];
// 删除对应的cell 更新UI
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationMiddle];
}
}else{
// 增加
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:@"悟空",@"name",@"男",@"age",@"八戒",@"hobby",@"18833336666",@"phoneNumber",12,@"age",@"八戒.png",@"picture", nil];
// 找到对应的分组
NSMutableArray *array = _dataDictionary[_dataArray[indexPath.section]];
// 添加元素
[array insertObject:dic atIndex:indexPath.row+1];
// 增加 更新UI
// <1 定义一个新路径
NSIndexPath *newPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
[_tableView insertRowsAtIndexPaths:@[newPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
复制代码
移动UITableViewCell
使页面处于可编辑状态
// 第一步 使页面处于可编辑状态
-(void)setEditing:(BOOL)editing animated:(BOOL)animated{
[super setEditing:editing animated:animated];
[_tableView setEditing:editing animated:animated];
self.navigationItem.rightBarButtonItem.title = editing? @"完成":@"编辑";
}
复制代码
指定tableView哪些行可以被移动
// 第二步 指定tableView哪些行可以被移动
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath{
return YES;
}
复制代码
移动完成
// 第三步 移动完成
-(void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath{
// 获取移动的数据
NSMutableArray *array = _dataDictionary[_dataArray[sourceIndexPath.section]];
// 获取移动的对象
NSDictionary *dic = [array objectAtIndex:sourceIndexPath.row];
// 先删除
[array removeObjectAtIndex:sourceIndexPath.row];
// 再添加
[array insertObject:dic atIndex:destinationIndexPath.row];
}
复制代码
检测跨区移动
// 检测跨区移动
-(NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath{
// 如果就在一个分区,则允许任意移动
if (sourceIndexPath.section == proposedDestinationIndexPath.section) {
return proposedDestinationIndexPath;
}
// 否则原路滚回去
return sourceIndexPath;
}
复制代码
常用的方法还有
// 快速索引
- (nullable NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView;
复制代码
UITableViewDelegate中常用方法
// 设置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码
// 设置分区的header高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
复制代码
// 设置分区的footer高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;
复制代码
// 设置分区headerView的视图(设置之后,与titleForHeader方法不共存且设置的高度没有用,想要确定,headerView的高度,必须重写heightForHeaderInSection方法)
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section;
复制代码
// 设置分区footerView的视图
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section;
复制代码
// 点击触发事件
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码
刷新UITableView
试想一下,当我们创建UITableView完成之后,我们向其中添加或者更改删除了一条数据,我们想让最新的数据呈现出来该怎么办呢?很自然的我们就想到了重新加载一遍,也就是刷新了.
关于刷新数据系统提供给我们三种方法.
// 刷新整个表格
-(void)reloadData;
复制代码
// 刷新某些section,animation表示刷新时使用的动画
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
复制代码
// 刷新某些row
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
复制代码
UITableViewController
上面说了这么多,我们发现创建一个表视图真的好麻烦,要设置代理和数据源,还有那么多的方法.那么有没有一种更好的方法来替代这些方法呢?答案当然是肯定的.为了提高开发效率,Apple将UITableView和UIViewController结合,产生了UITableViewController.
使用UITableViewController,我们只需要根据需要使用其方法进行配置就好了.如果搞懂了UITableView,那么使用UITableViewController就得心应手了,其实这两个如出一辙,在此就不赘述了.
总结
以上就是UITableView和UITableViewCell的简单介绍,如果有疑问或者错误,欢迎指正交流,我将不胜感激.转载请保留链接.