做为在开发中最经常使用的一个控件,UITableView也是在整个UIKit中比较复杂的一个,咱们须要记的东西也特别多.另外苹果官方为咱们提供了UITableViewController这个类,可是在这里咱们不使用它.而是在UIViewController上面添加一个UITableView.数组
UITableView继承于UIScrollView,当须要展现的数据量不少的时候,它是能够滚动显示的.bash
表视图的每一行都是由单元格(UITableViewCell)表示的.当咱们要对数据分组显示时,苹果为咱们提供了两种基本样式的显示,一种是分组样式,一种则为简单样式.ide
咱们初始化一个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的分割线和行高,一块儿头尾视图,索引条这几个属性进行了相关设置,对于其余的属性,读者能够本身根据兴趣尝试设置.ui
在UITableView中用于展现数据的主要就是UITableViewCell.在这里首相我想先说一下关于UITableViewCell的重用.spa
若是咱们想利用UITableView展现几条数据的话,咱们能够依次建立这些数量的行来展现这些数据,可是咱们若是有10000行甚至更多的数据要用来向用户展现呢?若是反复建立是十分消耗内存的.代理
这样咱们就天然的想到,为何要建立这么屡次cell呢?咱们为何不将建立好的cell保存起来,放在一个队列中重用呢?这就是UITableViewCell的重用机制.当咱们有10000条数据须要展现的时候,咱们使用这个机制建立的行可能仅须要10个,这样就大大节约了内存.code
咱们能够从官方的API中看到UITableViewCell的初始化方法.cdn
![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表明UITableView的索引.因为咱们建立的cell是重用的,这样一来咱们便无法精确的肯定这个行.出于此,系统为咱们提供了一个标示行的类,就是NSIndexPath
NSIndexPath的经常使用属性有:
row表示分区中的行的索引,section标示分区的索引.经过这两个属性咱们就能够找到想要的行.
关于UITableViewCell咱们是能够根据本身的须要自定义的,咱们只须要从新建立一个类继承自UITableViewCell,在其中设置成须要的样式.而后在注册和建立的时候使用自定义的cell就能够了,在这里咱们假设咱们建立一个MyTableViewCell,而且设置了重用标识符,那么注册和建立的方式以下.
注册
[self.tableView registerClass:[MyTableViewCell class] forCellReuseIdentifier:identifier];
复制代码
建立
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
复制代码
上面是对UITableView的总体结构介绍,若是咱们要建立表视图展现数据,咱们必需要为表视图设置代理和数据源,也就是UITableViewDelegate和UITableViewDataSource
先看数据源代理,数据源顾名思义,就是为表视图提供相关的数据.
咱们看到API中有两个必需要实现的方法
//分区的个数,也就设置这个表分红几组(section)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
//建立或者重用cell的代理方法
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
复制代码
另外咱们能够对其每一个分区的行数(row)进行设置,还能够设置其头尾(titleForHeaderInSection和titleForFooterInSection).
相对这些我跟想跟你们交流的是一些有趣的方法
使页面处于可编辑状态
// 第一步: 使页面处于可编辑状态
- (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];
}
}
复制代码
使页面处于可编辑状态
// 第一步 使页面处于可编辑状态
-(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完成以后,咱们向其中添加或者更改删除了一条数据,咱们想让最新的数据呈现出来该怎么办呢?很天然的咱们就想到了从新加载一遍,也就是刷新了.
关于刷新数据系统提供给咱们三种方法.
// 刷新整个表格
-(void)reloadData;
复制代码
// 刷新某些section,animation表示刷新时使用的动画
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
复制代码
// 刷新某些row
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
复制代码
上面说了这么多,咱们发现建立一个表视图真的好麻烦,要设置代理和数据源,还有那么多的方法.那么有没有一种更好的方法来替代这些方法呢?答案固然是确定的.为了提升开发效率,Apple将UITableView和UIViewController结合,产生了UITableViewController.
使用UITableViewController,咱们只须要根据须要使用其方法进行配置就行了.若是搞懂了UITableView,那么使用UITableViewController就驾轻就熟了,其实这两个一模一样,在此就不赘述了.
以上就是UITableView和UITableViewCell的简单介绍,若是有疑问或者错误,欢迎指正交流,我将不胜感激.转载请保留连接.