Inheritance
NSObject
UIResponder
UIView
UIScrollView
UITableView
一、UITableView多行刪除
- NSArray(NSMutableArray)的2個實(shí)用方法
- 選中某一行后加入刪除數(shù)據(jù)數(shù)組
- 點(diǎn)擊NavigationBar右側(cè)的Item執(zhí)行的方法
二、UITableView結(jié)合搜索功能
- 搜索的控件
- 為搜索框添加數(shù)據(jù)源, 在UISearchResultsUpdating協(xié)議實(shí)現(xiàn)
- 判斷是否在搜索,根據(jù)屬性"isSearch"改寫一些方法
- 發(fā)現(xiàn)問題, 去之前的地方修改
- 給表格添加右側(cè)的索引(SectionIndex)
三、自定義UITableView每個Section的header,模擬QQ好友界面分組的點(diǎn)擊展開收攏
- 當(dāng)前選中的section, 初始值默認(rèn)為0
- 在創(chuàng)建tableView的時候設(shè)置背景視圖
- 顯示表格的每個section的header
- 返回每一組有多少行
- ?點(diǎn)擊headView之后去判斷點(diǎn)擊的Section和之前已選中的Section的關(guān)系
一、UITableView多行刪除
NSArray(NSMutableArray)的2個實(shí)用方法 :
- (void)removeObjectsInArray:(NSArray *)array
- (BOOL)containsObject:(id)anObject
-
將要刪除的數(shù)據(jù)
@property (nonatomic, strong) NSMutableArray *deleteArray; -
為視圖添加刪除按鈕
// 點(diǎn)擊進(jìn)入表格多行選擇的狀態(tài)
UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"刪除" style:UIBarButtonItemStyleDone target:self action:@selector(beginDelete:)];
self.navigationItem.rightBarButtonItem = rightItem;
// 刪除數(shù)據(jù)數(shù)組的初始化
_deleteArray = [NSMutableArray array];
-
默認(rèn)是刪除狀態(tài), 我們要修改為可以多選的編輯狀態(tài)
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}
```
-
選中某一行后加入刪除數(shù)據(jù)數(shù)組
判斷是否是在編輯模式下的點(diǎn)擊: 沒有判斷的話, 在非多選狀態(tài)下選中一條cell, 進(jìn)入再退出編輯狀態(tài)就會產(chǎn)生bug刪除之前選中過的cell
判斷是否已經(jīng)加入過刪除數(shù)據(jù)數(shù)組- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (tableView.editing == YES) { // 如果沒有這句判斷的話, 在非多選狀態(tài)下選中一條cell, 進(jìn)入再退出編輯狀態(tài)就會產(chǎn)生bug刪除之前選中過的cell
// 獲取選擇的對象
StudentModel *model = self.dataArray[indexPath.row];
if (![self.deleteArray containsObject:model]) {
// 添加到刪除數(shù)據(jù)數(shù)組
[self.deleteArray addObject:model];
}
}
}
// 取消選擇, 表示不需要刪除該數(shù)據(jù)
-
(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
-
點(diǎn)擊NavigationBar右側(cè)的Item執(zhí)行的方法
- (void)beginDelete:(id)sender { // 獲取導(dǎo)航按鈕上的文字 NSString *title = self.navigationItem.rightBarButtonItem.title; **if ([title isEqualToString:@"刪除"])** { // 進(jìn)入表格的多選狀態(tài) [self.tbView setEditing:YES animated:YES]; // 將導(dǎo)航按鈕文字改為"確定" self.navigationItem.rightBarButtonItem.title = @"確定"; } **else { // 文字為"確定"** // 執(zhí)行刪除操作 // 從數(shù)據(jù)源數(shù)組中刪除需要刪除的數(shù)據(jù) [self.dataArray removeObjectsInArray:self.deleteArray]; // 取消表格的編輯狀態(tài) [self.tbView setEditing:NO]; // 刷新表格 [self.tbView reloadData]; // 將導(dǎo)航文字恢復(fù)成"刪除" self.navigationItem.rightBarButtonItem.title = @"刪除"; } }
二、UITableView結(jié)合搜索功能
// 創(chuàng)建搜索視圖
// iOS7: UISearchDisplayController 已不建議使用
// iOS8: UISearchController
-
搜索的控件
@property (nonatomic, strong) UISearchController *searchCtrl;
* #### 創(chuàng)建搜索控件
```
- (void)createSearch
{
// 1. 存nil表示當(dāng)前搜索結(jié)果就保存在當(dāng)前視圖控制器中, 而非是其他視圖控制器
_searchCtrl = [[UISearchController alloc] initWithSearchResultsController:nil];
// 2. 設(shè)置代理
_searchCtrl.delegate = self;
// 3. 設(shè)置搜索數(shù)據(jù)更新的代理:怎樣顯示搜索結(jié)果
_searchCtrl.searchResultsUpdater = self;
// 4. 顯示搜索條
[_searchCtrl.searchBar sizeToFit];
// 5. 添加到父視圖
/*
tableHeaderView: 表格的表頭, 顯示在整個表格的上面
tableFooterView: 表格的表尾, 顯示在整個表格的下面
*/
_tbView.tableHeaderView = _searchCtrl.searchBar;
// 這樣實(shí)現(xiàn), 搜索結(jié)果也是顯示到_tbView中
// _tbView顯示的數(shù)據(jù), 就要區(qū)分是在搜索時, 還是非搜索的時候
}
-
為搜索框添加數(shù)據(jù)源, 在UISearchResultsUpdating協(xié)議實(shí)現(xiàn)
// 存儲符合搜索條件的數(shù)據(jù)
@property (nonatomic, strong) NSMutableArray *searchResultArray;
* #### 在搜索框里面的文字修改時調(diào)用
* #### 在這個方法里面實(shí)現(xiàn)搜索的功能
```
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// 如果搜索結(jié)果數(shù)組沒有初始化, 初始化數(shù)組對象
if (self.searchResultArray == nil) {
_searchResultArray = [NSMutableArray array];
}
// 實(shí)現(xiàn)搜索的功能
// 獲取搜索的關(guān)鍵字
NSString *keyword = self.searchCtrl.searchBar.text;
// 從_dataArray數(shù)組里面找符合條件的數(shù)據(jù)
for (NSArray *sectionArray in self.dataArray) {
// 遍歷每一個section里面的內(nèi)容
for (NSString *title in sectionArray) {
// NSCaseInsensitiveSearch表示大小寫不敏感: a與A,a都可以匹配
NSRange range = [title rangeOfString:keyword options:NSCaseInsensitiveSearch];
if (range.location != NSNotFound) {
// 符合條件, 添加到搜索結(jié)果數(shù)組中
[self.searchResultArray addObject:title];
}
}
}
// 顯示數(shù)據(jù)
[self.tbView reloadData];
}
```
-
判斷是否在搜索
@property (nonatomic, assign) BOOL isSearch;
* 首先根據(jù)當(dāng)前搜索狀態(tài)給"isSearch"賦值
// 進(jìn)入搜索狀態(tài)
- (void)willPresentSearchController:(UISearchController *)searchController
{
self.isSearch = 1;
[self.tbView reloadData];
}
// 退出搜索狀態(tài)
- (void)willDismissSearchController:(UISearchController *)searchController
{
// 結(jié)束搜索狀態(tài)
self.isSearch = 0;
[self.tbView reloadData];
}
* #### 根據(jù)屬性"*isSearch*"改寫一些方法
// 返回多少組
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
**if (self.isSearch) {
// 搜索時顯示一組
return 1;
}**
return self.dataArray.count;
}
```
```
// 返回每組多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
**if (self.isSearch) {
// 搜索時返回的行數(shù)
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];
}
// 顯示數(shù)據(jù)
cell.textLabel.text = self.searchResultArray[indexPath.row];
return cell;
}**
原代碼
}
```
```
// 每個Section的標(biāo)題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (self.isSearch) {
return @"搜索結(jié)果";
}
return [NSString stringWithFormat:@"第%c組", (int)section+'A'];
}
```
---
#### 發(fā)現(xiàn)問題, 去之前的地方修改
1. #### 修改UISearchController的屬性
1. 使搜索結(jié)果滑動: 隱藏前面的遮罩視圖
` _searchCtrl.dimsBackgroundDuringPresentation = NO;`
2. 在搜索的時候顯示導(dǎo)航欄
`_searchCtrl.hidesNavigationBarDuringPresentation = NO;`
2. #### 修改搜索詞時重新刷新tableView
// 在搜索框里面的文字修改時調(diào)用
// 在這個方法里面實(shí)現(xiàn)搜索的功能
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController
{
// 如果搜索結(jié)果數(shù)組沒有初始化, 初始化數(shù)組對象
if (self.searchResultArray == nil) {
_searchResultArray = [NSMutableArray array];
}
else {
[self.searchResultArray removeAllObjects];
}
---
* #### 給表格添加右側(cè)的索引(*SectionIndex*)
1. **表格右側(cè)索引的文字**
```
//返回索引上面顯示的文字內(nèi)容
//實(shí)現(xiàn)這個方法,系統(tǒng)或默認(rèn)在右側(cè)添加索引視圖
//點(diǎn)擊相應(yīng)地文字會跳轉(zhuǎn)到對應(yīng)的section
//這種對應(yīng)關(guān)系是按照順序?qū)?yīng)的
//索引視圖默認(rèn)比較小,如果需要的話,可以自己去實(shí)現(xiàn)這個功能
/*
自己實(shí)現(xiàn)功能的思路:
添加一個視圖,放在表格視圖的右邊
在上面添加很多按鈕
點(diǎn)擊按鈕的事件中,設(shè)置表格視圖的偏移量
//計(jì)算位置
//header的高度和cell的高度
//_tbView scrollToRowAtIndexPath:<#(NSIndexPath *)#> atScrollPosition:<#(UITableViewScrollPosition)#> animated:<#(BOOL)#>
*/
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSMutableArray *array = [NSMutableArray array];
//26個組對應(yīng)的索引上面的標(biāo)題分別是每個字母的大寫
for (int i='A'; i<='Z'; i++) {
[array addObject:[NSString stringWithFormat:@"%c",i]];
}
return array;
}
```
2. **實(shí)現(xiàn)另外一個代理方法,可以修改點(diǎn)擊右邊index項(xiàng)對應(yīng)跳轉(zhuǎn)的tableView的section順序**
```
- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
//參數(shù)中的index是索引數(shù)組里面的序號
//返回的值是表格視圖的section的序號
return index;
}
```
* #### 為搜索框在右側(cè)的*"sectionIndexTitles"*增加一個索引
-
(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
NSMutableArray *indexArray = [NSMutableArray array];// 對應(yīng)搜索框的索引
[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
{
// 參數(shù)中的index是索引數(shù)組里面的序號
// 返回的值是表格視圖的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好友界面分組的點(diǎn)擊展開收攏
* #### 當(dāng)前選中的section, 初始值默認(rèn)為0
`@property (nonatomic, assign) NSInteger selectSection;`
* #### 在創(chuàng)建tableView的時候設(shè)置背景視圖
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"];
// 創(chuàng)建標(biāo)簽, 顯示在第幾組
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(80, 0, 120, 40)];
label.text = [NSString stringWithFormat:@"第%ld組", section + 1];
[headerImageView addSubview:label];
// 添加一個圖片, 顯示展開的狀態(tài)
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];
// 點(diǎn)擊的功能
// 添加一個手勢
// 打開用戶交互
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) {
//選中的組里面的內(nèi)容全部顯示
NSArray *sectionArray = _dataArray[section];
return sectionArray.count;
}else{
//沒有選中的組cell全部不顯示,只顯示header
return 0;
}
}
```
* #### 點(diǎn)擊headView之后去判斷點(diǎn)擊的Section和之前已選中的Section的關(guān)系
```
- (void)tapAction:(UIGestureRecognizer *)g
{
//獲取點(diǎn)擊的section
UIImageView *headerView = (UIImageView *) g.view;
NSInteger section = headerView.tag-200;
NSLog(@"section:%ld",section);
//賦值給選中section的成員變量
if (section == _selectSection) {
//點(diǎn)擊的是已經(jīng)展開的組
//將展開的組關(guān)閉
_selectSection = -1;
[_tbView reloadData];
}else{
//點(diǎn)擊的是關(guān)閉的組
//將已經(jīng)展開的組合并,將點(diǎn)擊的組展開
_selectSection = section;
[_tbView reloadData];
}
}
```