D12:UITableView(多行刪除_UISearchBar_自定義Section的header)

Inheritance

NSObject
UIResponder
UIView
UIScrollView
UITableView

一、UITableView多行刪除

  1. NSArray(NSMutableArray)的2個實(shí)用方法
  2. 選中某一行后加入刪除數(shù)據(jù)數(shù)組
  3. 點(diǎn)擊NavigationBar右側(cè)的Item執(zhí)行的方法

二、UITableView結(jié)合搜索功能

  1. 搜索的控件
  2. 為搜索框添加數(shù)據(jù)源, 在UISearchResultsUpdating協(xié)議實(shí)現(xiàn)
  3. 判斷是否在搜索,根據(jù)屬性"isSearch"改寫一些方法
  4. 發(fā)現(xiàn)問題, 去之前的地方修改
  5. 給表格添加右側(cè)的索引(SectionIndex)

三、自定義UITableView每個Section的header,模擬QQ好友界面分組的點(diǎn)擊展開收攏

  1. 當(dāng)前選中的section, 初始值默認(rèn)為0
  2. 在創(chuàng)建tableView的時候設(shè)置背景視圖
  3. 顯示表格的每個section的header
  4. 返回每一組有多少行
  5. ?點(diǎn)擊headView之后去判斷點(diǎn)擊的Section和之前已選中的Section的關(guān)系

一、UITableView多行刪除

NSArray(NSMutableArray)的2個實(shí)用方法 :

- (void)removeObjectsInArray:(NSArray *)array

- (BOOL)containsObject:(id)anObject

  1. 將要刪除的數(shù)據(jù)

    @property (nonatomic, strong) NSMutableArray *deleteArray;
    
  2. 為視圖添加刪除按鈕

    // 點(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];        
  1. 默認(rèn)是刪除狀態(tài), 我們要修改為可以多選的編輯狀態(tài)

    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
    

{
return UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert;
}
```

  1. 選中某一行后加入刪除數(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];
      }
      }

  2. 點(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

  1. 搜索的控件

@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];
        }
        
    }
    ```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容