Inheritance
NSObject
UIResponder
UIView
UIScrollView
UITableView
一、UITableView多行删除
- NSArray(NSMutableArray)的2个实用方法
- 选中某一行后加入删除数据数组
- 点击NavigationBar右侧的Item执行的方法
二、UITableView结合搜索功能
- 搜索的控件
- 为搜索框添加数据源, 在UISearchResultsUpdating协议实现
- 判断是否在搜索,根据属性"isSearch"改写一些方法
- 发现问题, 去之前的地方修改
- 给表格添加右侧的索引(SectionIndex)
三、自定义UITableView每个Section的header,模拟QQ好友界面分组的点击展开收拢
- 当前选中的section, 初始值默认为0
- 在创建tableView的时候设置背景视图
- 显示表格的每个section的header
- 返回每一组有多少行
- �点击headView之后去判断点击的Section和之前已选中的Section的关系
一、UITableView多行删除
NSArray(NSMutableArray)的2个实用方法 :
- (void)removeObjectsInArray:(NSArray *)array
- (BOOL)containsObject:(id)anObject
-
将要删除的数据
@property (nonatomic, strong) NSMutableArray *deleteArray;
-
为视图添加删除按钮
// 点击进入表格多行选择的状态
UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"删除" style:UIBarButtonItemStyleDone target:self action:@selector(beginDelete:)];
self.navigationItem.rightBarButtonItem = rightItem;
// 删除数据数组的初始化
_deleteArray = [NSMutableArray array];
-
默认是删除状态, 我们要修改为可以多选的编辑状态
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}
```
-
选中某一行后加入删除数据数组
判断是否是在编辑模式下的点击: 没有判断的话, 在非多选状态下选中一条cell, 进入再退出编辑状态就会产生bug删除之前选中过的cell
判断是否已经加入过删除数据数组- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.editing == YES) { // 如果没有这句判断的话, 在非多选状态下选中一条cell, 进入再退出编辑状态就会产生bug删除之前选中过的cell
// 获取选择的对象
StudentModel *model = self.dataArray[indexPath.row];
if (![self.deleteArray containsObject:model]) {
// 添加到删除数据数组
[self.deleteArray addObject:model];
}
}
}
// 取消选择, 表示不需要删除该数据
-
(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
// 获取取消选择的对象
StudentModel *model = self.dataArray[indexPath.row];if ([self.deleteArray containsObject:model]) {
[self.deleteArray removeObject:model];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
-
点击NavigationBar右侧的Item执行的方法
- (void)beginDelete:(id)sender { // 获取导航按钮上的文字 NSString *title = self.navigationItem.rightBarButtonItem.title; **if ([title isEqualToString:@"删除"])** { // 进入表格的多选状态 [self.tbView setEditing:YES animated:YES]; // 将导航按钮文字改为"确定" self.navigationItem.rightBarButtonItem.title = @"确定"; } **else { // 文字为"确定"** // 执行删除操作 // 从数据源数组中删除需要删除的数据 [self.dataArray removeObjectsInArray:self.deleteArray]; // 取消表格的编辑状态 [self.tbView setEditing:NO]; // 刷新表格 [self.tbView reloadData]; // 将导航文字恢复成"删除" self.navigationItem.rightBarButtonItem.title = @"删除"; } }
二、UITableView结合搜索功能
// 创建搜索视图
// iOS7: UISearchDisplayController 已不建议使用
// iOS8: UISearchController
-
搜索的控件
@property (nonatomic, strong) UISearchController *searchCtrl;
* #### 创建搜索控件
```
- (void)createSearch
{
// 1. 存nil表示当前搜索结果就保存在当前视图控制器中, 而非是其他视图控制器
_searchCtrl = [[UISearchController alloc] initWithSearchResultsController:nil];
// 2. 设置代理
_searchCtrl.delegate = self;
// 3. 设置搜索数据更新的代理:怎样显示搜索结果
_searchCtrl.searchResultsUpdater = self;
// 4. 显示搜索条
[_searchCtrl.searchBar sizeToFit];
// 5. 添加到父视图
/*
tableHeaderView: 表格的表头, 显示在整个表格的上面
tableFooterView: 表格的表尾, 显示在整个表格的下面
*/
_tbView.tableHeaderView = _searchCtrl.searchBar;
// 这样实现, 搜索结果也是显示到_tbView中
// _tbView显示的数据, 就要区分是在搜索时, 还是非搜索的时候
}
-
为搜索框添加数据源, 在UISearchResultsUpdating协议实现
// 存储符合搜索条件的数据
@property (nonatomic, strong) NSMutableArray *searchResultArray;
* #### 在搜索框里面的文字修改时调用
* #### 在这个方法里面实现搜索的功能
```
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// 如果搜索结果数组没有初始化, 初始化数组对象
if (self.searchResultArray == nil) {
_searchResultArray = [NSMutableArray array];
}
// 实现搜索的功能
// 获取搜索的关键字
NSString *keyword = self.searchCtrl.searchBar.text;
// 从_dataArray数组里面找符合条件的数据
for (NSArray *sectionArray in self.dataArray) {
// 遍历每一个section里面的内容
for (NSString *title in sectionArray) {
// NSCaseInsensitiveSearch表示大小写不敏感: a与A,a都可以匹配
NSRange range = [title rangeOfString:keyword options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
// 符合条件, 添加到搜索结果数组中
[self.searchResultArray addObject:title];
}
}
}
// 显示数据
[self.tbView reloadData];
}
```
-
判断是否在搜索
@property (nonatomic, assign) BOOL isSearch;
* 首先根据当前搜索状态给"isSearch"赋值
// 进入搜索状态
- (void)willPresentSearchController:(UISearchController *)searchController
{
self.isSearch = 1;
[self.tbView reloadData];
}
// 退出搜索状态
- (void)willDismissSearchController:(UISearchController *)searchController
{
// 结束搜索状态
self.isSearch = 0;
[self.tbView reloadData];
}
* #### 根据属性"*isSearch*"改写一些方法
// 返回多少组
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
**if (self.isSearch) {
// 搜索时显示一组
return 1;
}**
return self.dataArray.count;
}
```
```
// 返回每组多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
**if (self.isSearch) {
// 搜索时返回的行数
return self.searchResultArray.count;
}**
return [self.dataArray[section] count];
}
```
```
// 返回cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
**if (self.isSearch) {
// 搜索时
static NSString *SearchCellID = @"Search";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SearchCellID];
if (nil == cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SearchCellID];
}
// 显示数据
cell.textLabel.text = self.searchResultArray[indexPath.row];
return cell;
}**
原代码
}
```
```
// 每个Section的标题
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (self.isSearch) {
return @"搜索结果";
}
return [NSString stringWithFormat:@"第%c组", (int)section+'A'];
}
```
---
#### 发现问题, 去之前的地方修改
1. #### 修改UISearchController的属性
1. 使搜索结果滑动: 隐藏前面的遮罩视图
` _searchCtrl.dimsBackgroundDuringPresentation = NO;`
2. 在搜索的时候显示导航栏
`_searchCtrl.hidesNavigationBarDuringPresentation = NO;`
2. #### 修改搜索词时重新刷新tableView
// 在搜索框里面的文字修改时调用
// 在这个方法里面实现搜索的功能
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// 如果搜索结果数组没有初始化, 初始化数组对象
if (self.searchResultArray == nil) {
_searchResultArray = [NSMutableArray array];
}
else {
[self.searchResultArray removeAllObjects];
}
---
* #### 给表格添加右侧的索引(*SectionIndex*)
1. **表格右侧索引的文字**
```
//返回索引上面显示的文字内容
//实现这个方法,系统或默认在右侧添加索引视图
//点击相应地文字会跳转到对应的section
//这种对应关系是按照顺序对应的
//索引视图默认比较小,如果需要的话,可以自己去实现这个功能
/*
自己实现功能的思路:
添加一个视图,放在表格视图的右边
在上面添加很多按钮
点击按钮的事件中,设置表格视图的偏移量
//计算位置
//header的高度和cell的高度
//_tbView scrollToRowAtIndexPath:<#(NSIndexPath *)#> atScrollPosition:<#(UITableViewScrollPosition)#> animated:<#(BOOL)#>
*/
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSMutableArray *array = [NSMutableArray array];
//26个组对应的索引上面的标题分别是每个字母的大写
for (int i='A'; i<='Z'; i++) {
[array addObject:[NSString stringWithFormat:@"%c",i]];
}
return array;
}
```
2. **实现另外一个代理方法,可以修改点击右边index项对应跳转的tableView的section顺序**
```
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
//参数中的index是索引数组里面的序号
//返回的值是表格视图的section的序号
return index;
}
```
* #### 为搜索框在右侧的*"sectionIndexTitles"*增加一个索引
-
(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSMutableArray *indexArray = [NSMutableArray array];// 对应搜索框的索引
[indexArray addObject:UITableViewIndexSearch];for (int i = 0; i < 26; i++) {
[indexArray addObject:[NSString stringWithFormat:@"%c", 'A'+i]];
}
return indexArray;
} -
(NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
// 参数中的index是索引数组里面的序号
// 返回的值是表格视图的section序号// 表格的section 索引的序号
//搜索:-1 0
//A: 0 1
//B: 1 2
if (index == 0) {
// 搜索的索引
self.tbView.contentOffset = CGPointZero;
return -1;
} else {
return index-1;
}
}
---
## 三、自定义UITableView每个Section的header,模拟QQ好友界面分组的点击展开收拢
* #### 当前选中的section, 初始值默认为0
`@property (nonatomic, assign) NSInteger selectSection;`
* #### 在创建tableView的时候设置背景视图
UIImageView *bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"gamebg"]];
bgImageView.frame = _tbView.bounds;
_tbView.backgroundView = bgImageView;
* #### 显示表格的每个section的header
```
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// section的header的背景视图
UIImageView *headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
headerImageView.image = [UIImage imageNamed:@"header"];
// 创建标签, 显示在第几组
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(80, 0, 120, 40)];
label.text = [NSString stringWithFormat:@"第%ld组", section + 1];
[headerImageView addSubview:label];
// 添加一个图片, 显示展开的状态
UIImageView *leftImageView = [[UIImageView alloc] initWithFrame:CGRectMake(20, 0, 40, 40)];
if (section == self.selectSection) {
// 选中的图片
leftImageView.image = [UIImage imageNamed:@"list_ico_d"];
} else {
// 未选中的图片
leftImageView.image = [UIImage imageNamed:@"list_ico"];
}
[headerImageView addSubview:leftImageView];
// 点击的功能
// 添加一个手势
// 打开用户交互
UITapGestureRecognizer *g = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
[headerImageView addGestureRecognizer:g];
headerImageView.userInteractionEnabled = YES;
headerImageView.tag = 200+section;
return headerImageView;
}
```
* #### 返回每一组有多少行
```
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == _selectSection) {
//选中的组里面的内容全部显示
NSArray *sectionArray = _dataArray[section];
return sectionArray.count;
}else{
//没有选中的组cell全部不显示,只显示header
return 0;
}
}
```
* #### 点击headView之后去判断点击的Section和之前已选中的Section的关系
```
- (void)tapAction:(UIGestureRecognizer *)g
{
//获取点击的section
UIImageView *headerView = (UIImageView *) g.view;
NSInteger section = headerView.tag-200;
NSLog(@"section:%ld",section);
//赋值给选中section的成员变量
if (section == _selectSection) {
//点击的是已经展开的组
//将展开的组关闭
_selectSection = -1;
[_tbView reloadData];
}else{
//点击的是关闭的组
//将已经展开的组合并,将点击的组展开
_selectSection = section;
[_tbView reloadData];
}
}
```