UITableView【表格视图】
UITableView是表格视图,是UIScrollView的子类,非常重要。
一、表格视图常用属性
1、基本属性方法
创建一个tableView
// UITableViewStylePlain, //扁平风格的
// UITableViewStyleGrouped //跟系统设置风格是一样的 分组风格
UITableView *tableView = [[UITableView alloc]initWithFrame:self.view.frame style:UITableViewStyleGrouped];
表格的背景颜色
tableView.backgroundColor = [UIColor orangeColor];
如果根视图是导航视图控制器,则需要取消导航控制器对布局的影响
方法一:
//让导航条透明(原点坐标是从屏幕左上角开始的),scrollview(子类) 正常显示
self.automaticallyAdjustsScrollViewInsets = NO;
CGRect tableViewFrame = tableView.frame ;
tableViewFrame.origin.y += 64;
tableViewFrame.size.height -= 64;
tableView.frame = tableViewFrame;
方法二:
//取消导航视图控制器 对布局(第一个子视图是UIScrollview的子类)的影响
// 设置UIRectEdgeNone 之后,你发发现 self.view 零点是导航栏下边开始的
self.edgesForExtendedLayout = UIRectEdgeNone;
CGRect tableViewFrame = tableView.frame ;
tableViewFrame.size.height -= 64;
tableView.frame = tableViewFrame;
分割线的类型
UITableViewCellSeparatorStyleNone, 没有(一般情况下,做一些比较复杂cell 分割线是不显示,自己可以定制一条分割线)
UITableViewCellSeparatorStyleSingleLine,细线
UITableViewCellSeparatorStyleSingleLineEtched 没有
tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
分割线颜色
tableView.separatorColor = [UIColor redColor];
设置分割线边界的
tableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);
tableview 的头视图 和 尾视图 是一个UIView类型的
tableView.tableHeaderView
tableView.tableFooterView
2、数据代理方法
UITableViewDataSource 数据源协议,告诉tableView 要显示多少行和每一行要显示内容
设置代理
tableView.dataSource = self;
代理方法必须实现的方法 (行数和内容)
//设置第section组的行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.dataSource[section] count];
}
//设置cell 内容(行内容)
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//创建一个cell
//第一个参数 cell的风格
//第二个参数 唯一标示符 用来复用cell的,怎么复用呢,只创建比我们能看到屏幕上cell 多一点,每当我们下滑动的时候,会多的cell 拿过来用。系统会创建一个复用的队列,每当需要创建cell的时候,会先去队列里面找有没有可用的cell(cellID是一样的),如果有可用的,就拿过来用,如果没有可用的cell,就直接创建一个。
//先检测复用队列,有没有可以用cell
static NSString *cellID = @"cellID";
//检测对应id 有没有对应的可用cell
UITableViewCell *reuseCell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (reuseCell == nil) {
不存在可以复用cell,就去创建一个
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellID];
}
cell自带了一个label 和imageView
cell的类型:
UITableViewCellStyleDefault 有两个label
UITableViewCellStyleValue1,(系统的设置风格)
UITableViewCellStyleValue2,(跟系统联系人的风格相似)(图片不会显示)
UITableViewCellStyleSubtitle
NSString *name = self.dataSource[indexPath.section][indexPath.row];
cell.textLabel.text = name;
//设置图片
cell.imageView.image = [UIImage imageNamed:@"2"];
//详细信息label
cell.detailTextLabel.text = @"详细信息";
//cell的内容视图(放自定义控件)
cell.contentView.backgroundColor = [UIColor cyanColor];
//指示附加视图
cell.accessoryType = UITableViewCellAccessoryDetailButton;
//自己定制附加视图
cell.accessoryView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"3"]];
附件视图被点中会调用协议方法
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;
//点击cell之后的风格
// UITableViewCellSelectionStyleNone,
// UITableViewCellSelectionStyleBlue,
// UITableViewCellSelectionStyleGray,
// UITableViewCellSelectionStyleDefault
cell.selectionStyle = UITableViewCellSelectionStyleGray;
//设置选中的背景视图
UIView *selectedView = [[UIView alloc]init];
selectedView.backgroundColor = [UIColor blueColor];
cell.selectedBackgroundView = selectedView;
return cell;
}
//设置tableview 有多少组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.dataSource.count;
}
//分组的 index title
- (nullable NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return @[@"a",@"b",@"b",@"c",@"c"];
}
//改变 点击index title 所 跳到的组
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index {
if ([title isEqualToString:@"a"]) {
return 4;
}
return index;
}
3、本身代理方法
设置行、头视图,尾视图的高
设置头视图和尾视图 返回值UIView
设置头视图和尾视图的title 返回NSString
选中某一行
////设置组头
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIView *headerSectionView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
headerSectionView.backgroundColor = [UIColor yellowColor];
return headerSectionView;
}
////设置组尾视图
- (UIView*)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 50)];
view.backgroundColor = [UIColor greenColor];
return view;
}
////设置组头高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 100;
}
////组尾高度
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
return 100;
}
//设置组头title //粘性表头 tableview 的风格 必须是plain,组头组尾视图不能设置,系统默认的头尾视图。
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section;
//选了某一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//可以选中进去之后,在出来,cell 就不被选中
[tableView deselectRowAtIndexPath:indexPath animated:YES];
将选中的行的信息在另一个视图显示
DetailViewController *dvc = [[DetailViewController alloc]init];
//点击的那一行的 名字
NSString *name = self.dataSource [indexPath.section][indexPath.row];
dvc.name = name;
[self.navigationController pushViewController:dvc animated:YES];
}
代理
tableView.delegate = self;
// tableview 是继承于UIScrollview·的,所以UIscrollView的协议方法,tableView都能用
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
NSLog(@"scrollViewDidScroll");
}
二、表格视图的基本操作
1、 为了方便操作,创建了表格的基类,在基类中实现以后必须要用的方法(行,内容)和属型,必须在.h中声明属性和非类方法(后续需要不断使用的方法)
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSMutableArray *dataSource;
/**
* 创建数据源 子类取实现 需要重写
*/
- (void)createDataSource;
2、操作表格时需实现协议中的方法 对表格 提交编辑和 设置编辑(多行删除除外)
****************************************************************添加一行 AddCellViewController
(1) 首先,重写数据源 数据源单独作为一个类,创建多种数据源
- (void)createDataSource {
self.dataSource = [DataSourceStore createOPDataSource];
}
(2)根据数据源中数据存储的形式重写类方法cell
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *reusableCell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
reusableCell.textLabel.text = [NSString stringWithFormat:@"重写%@",self.dataSource[indexPath.row]] ;
return reusableCell;
}
(3)编辑表格
//编辑的风格
// UITableViewCellEditingStyleNone,
// UITableViewCellEditingStyleDelete,
// UITableViewCellEditingStyleInsert
// 提交编辑
//类方法
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleInsert) {
//首先要在数据源添加一个数据
[self.dataSource insertObject:@"添加的" atIndex:indexPath.row];
//刷新全部的数据
//[self.tableView reloadData];
//插入一行 刷新一行
[self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
else if (editingStyle == UITableViewCellEditingStyleDelete){
NSLog(@"删除");
}
}
//设置编辑风格
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleInsert;
}
****************************************************************删除一行 RemoveViewController
(1) 首先,重写数据源
(2 )编辑表格
//提交编辑
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
//先删除数据源的某个元素
[self.dataSource removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
//设置编辑类型
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete;
}
//iOS8的新属性,自定义左滑cell按钮
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
//行动作
// UITableViewRowActionStyleDefault = 0,
// UITableViewRowActionStyleDestructive = UITableViewRowActionStyleDefault,
// UITableViewRowActionStyleNormal
UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"置顶" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"点击置顶按钮");
}];
UITableViewRowAction *action2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
NSLog(@"点击删除按钮");
}];
return @[action1,action2];
}
**********************************************************************删除多行不需要编辑表格和提交编辑,需要直接重写item“编辑”的触发事件
(1) 首先,重写数据源
(2 )重写导航栏的“编辑”item的触发事件
//设置编辑
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
}
//用两个协议方法来记录选中和撤销
//撤销选中行
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
}
//选中行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
//只有是编辑模式的时候我们才去几乎选中的行
if (tableView.isEditing) {
}
//有一个专门记录选中的行数
// tableView.indexPathsForSelectedRows;
// NSLog(@"%ld",tableView.indexPathsForSelectedRows.count);
}
- (void)itemPressed:(UIBarButtonItem*)item {
NSLog(@"强制重写");
if (self.tableView.isEditing) {
//在这里处理多选删除
//先删除数据源
//多选删除的时候必须要倒序删除
//1、先把数组里边的元素排序
NSArray *resultArray = [self.tableView.indexPathsForSelectedRows sortedArrayUsingSelector:@selector(compare:)];
//按照数组里边的内容 类型 compare: 方法进行排序,一般compare:都是从小到大排序
//逆序数组,首先逆序枚举,然后取出所有得元素
NSArray *reverseArray = [[resultArray reverseObjectEnumerator] allObjects];
for (NSIndexPath *indexpath in reverseArray) {
[self.dataSource removeObjectAtIndex:indexpath.row];
}
//刷新界面
[self.tableView deleteRowsAtIndexPaths:self.tableView.indexPathsForSelectedRows withRowAnimation:UITableViewRowAnimationAutomatic];
// self.tableView.editing = NO;
//带有动画效果
[self.tableView setEditing:NO animated:YES];
}
else {
//self.tableView.editing = YES;
[self.tableView setEditing:YES animated:YES];
}
}
***********************************************************************折叠FoldViewController
- (void)viewDidLoad {
[super viewDidLoad];
//初始化数组状态,设置section全是关闭
self.sectionsState = [NSMutableArray arrayWithObjects:@0,@0,@0,@0, nil];
// Do any additional setup after loading the view.
}
- (void)createDataSource {
self.dataSource = [DataSourceStore createFlodDataSource];
}
//两个重要的协议
//行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSNumber *state = self.sectionsState[section];
//如果是关闭的,返回0;
if (state.intValue == 0) {
return 0;
}
else{
//只要是打开的就返回数组里面的元素个数
return [self.dataSource[section] count];
}
}
//内容
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID";
UITableViewCell *reusableCell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (reusableCell == nil) {
reusableCell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
reusableCell.textLabel.text = self.dataSource[indexPath.section][indexPath.row];
return reusableCell;
}
//组数
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [self.dataSource count];
}
//设置组头
- (UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIButton *headerView = [UIButton buttonWithType:UIButtonTypeSystem];
headerView.frame = CGRectMake(0, 0, self.view.frame.size.width, 44);
[headerView setTitle:@"我的好友" forState:UIControlStateNormal];
headerView.backgroundColor = [UIColor greenColor];
[headerView addTarget:self action:@selector(headerViewPressed:) forControlEvents:UIControlEventTouchUpInside];
headerView.tag = section + 100;
return headerView;
}
- (void)headerViewPressed:(UIButton*)sender {
NSInteger section = sender.tag - 100;
BOOL state = [self.sectionsState[section] boolValue];
//修改数据源
NSNumber *currentState = state?@0:@1;
//如果是关着的就设置现在的状态为开,反之一样
[self.sectionsState replaceObjectAtIndex:section withObject:currentState];
//刷新对应的section
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];
//NSLog(@"点击了%ld头视图",section);
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
return 44.0;
}
****************************************************************** 移动 MoveViewController
(1) 首先,重写数据源
(2 )设置行可以移动
//让表格可以移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
return YES;
}
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewCellEditingStyleNone;
}
(3 )移动表格的行
//移动表格的协议方法
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
//改变数据源
[self.dataSource exchangeObjectAtIndex:sourceIndexPath.row withObjectAtIndex:destinationIndexPath.row];
}
*******************************************************************搜索 SearchViewController
首先必须遵守的两个协议UISearchBarDelegate,UISearchDisplayDelegate
为了方便使用,设置三个属性
@property (nonatomic, strong) UISearchBar *searchBar; 搜索栏
@property (nonatomic, strong) UISearchDisplayController *searchDC; 显示搜索结果
@property (nonatomic, strong) NSMutableArray *resultArray; 存放搜索的结果
(1)首先,创建视图,将搜索栏添加到表格的 表头 并设置协议的代理
- (void)createView {
_searchBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 44.0)];
_searchBar.placeholder = @"请输入";
self.tableView.tableHeaderView = _searchBar;
_searchDC = [[UISearchDisplayController alloc]initWithSearchBar:_searchBar contentsController:self];
_searchDC.searchResultsDelegate = self;
_searchDC.searchResultsDataSource= self;
}
(2)创建数据源
(3)实现tableView必须实现的两个协议方法(重写行数和内容)
’
//行数
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (tableView == self.tableView) {
return [self.dataSource count];
}
else{
//说明是searchBar的tableView
// //拿到搜索结果
// //谓词搜索
// //查询后面的字符串是否包含搜索内容
// NSPredicate *pd = [NSPredicate predicateWithFormat:@"self contains[cd]%@",_searchBar.text];
// //在我们的数据源查找
// NSArray *array1 = [self.dataSource filteredArrayUsingPredicate:pd];
// self.resultArray = [NSMutableArray arrayWithArray:array1];
//
// return self.resultArray.count ;
//第二种方法 ios8以后才能用
self.resultArray = [NSMutableArray new];
for (NSString *item in self.dataSource) {
BOOL contains = [item containsString:_searchBar.text];
if (contains) {
//只要包含 就添加到结果里边
[_resultArray addObject:item];
}
}
return self.resultArray.count;
}
}
//搜索内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = @"cellID";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
if (tableView == self.tableView) {
cell.textLabel.text = self.dataSource[indexPath.row];
}
else {
//就是我们的searchBar的tableView视图
cell.textLabel.text = self.resultArray[indexPath.row];
}
return cell;
}