iOS UITableView 多選刪除功能

一、概述

UITbableView作為列表展示信息,除了展示的功能,有時還會用到刪除,比如購物車收藏列表等。

  • 單行刪除:可以直接使用系統自帶的刪除功能,當橫向輕掃cell時,右側出現紅色的刪除按鈕,點擊刪除當前cell。或者讓表格進入編輯狀態后,點擊左側的紅色按鈕,右側出現刪除按鈕,即可刪除當前cell。可參照:iOS UITableView刪除功能
  • 多選刪除:點擊編輯按鈕,讓表格進入編輯狀態后,每行的左側出現一個小圓圈,當點擊行的時候,可以選中該行或者取消選中該行,當點擊刪除按鈕的時候才會把選中的行全部刪除掉。
二、效果圖
系統樣式效果圖.gif
三、技術分析
  1. 讓tableView進入編輯狀態,即tableView.editing = YES
// 取消
[self.tableView setEditing:YES animated:NO]; 
  1. 返回編輯模式,即實現UITableViewDelegate中的- tableview:editingStyleForRowAtIndexPath:方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert。如果不實現,默認返回的就是刪除模式即UITableViewCellEditingStyleDelete
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
        if (tableView.isEditing) {
            // 多選
            return UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert;
        }else{
            // 刪除
            return UITableViewCellEditingStyleDelete;
        }
}
  1. 返回編輯模式,即實現UITableViewDelegate中的- tableview:editingStyleForRowAtIndexPath:方法,在里面返回多選模式即UITableViewCellEditingStyleDelete | UITableViewCellEditingStyleInsert。如果不實現,默認返回的就是刪除模式即UITableViewCellEditingStyleDelete
// 選中
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
          if (tableView.isEditing) {
              NSIndexPath *indexPathM = self.dataSource[indexPath.row];
              if (![self.selectedDatas containsObject:indexPathM]) {
                  [self.selectedDatas addObject:indexPathM];
              }
              [self _indexPathsForSelectedRowsCountDidChange:tableView.indexPathsForSelectedRows];
              return;
          }
          MHOperationController *operation = [[MHOperationController alloc] init];
          NSIndexPath *indexP = self.dataSource[indexPath.row];
          operation.title = [NSString stringWithFormat:@"仙劍奇俠傳 第%zd集",indexP.row];
          [self.navigationController pushViewController:operation animated:YES];
}
// 取消選中
- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
          if (tableView.isEditing)
          {
              NSIndexPath *indexPathM = self.dataSource[indexPath.row];
              if ([self.selectedDatas containsObject:indexPathM]) {
              [self.selectedDatas removeObject:indexPathM];
              }
             [self _indexPathsForSelectedRowsCountDidChange:tableView.indexPathsForSelectedRows];
          }
}
  1. 點擊刪除按鈕,刪除數據源的數據和tableView中所對應的cell。
// delete收藏視頻
- (void)_deleteSelectIndexPaths:(NSArray *)indexPaths
{
        // 刪除數據源
        [self.dataSource removeObjectsInArray:self.selectedDatas];
        [self.selectedDatas removeAllObjects];
    
        // 刪除選中項
        [self.tableView beginUpdates];
        [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationFade];
        [self.tableView endUpdates];
    
        // 驗證數據源
        [self _indexPathsForSelectedRowsCountDidChange:self.tableView.indexPathsForSelectedRows];
    
        // 驗證沒有數據的情況  沒有數據 右側按鈕 不能點擊 細節處理
        if (self.dataSource.count == 0)
        {
            //沒有收藏數據
            if(self.rightBarButtonItem.selected)
            {
                // 編輯狀態 -- 取消編輯狀態
                [self _rightBarButtonItemDidClicked:self.rightBarButtonItem];
            }      
            self.rightBarButtonItem.enabled = NO;      
        }
}
四、細節處理
  1. 側滑狀態下點擊編輯按鈕的bug。
 // 編輯按鈕的點擊事件
 - (void)_rightBarButtonItemDidClicked:(UIButton *)sender
{
        sender.selected = !sender.isSelected;
        if (sender.isSelected) { 
            // 這個是fix掉:當你左滑刪除的時候,再點擊右上角編輯按鈕, cell上的刪除按鈕不會消失掉的bug。且必須放在 設置tableView.editing = YES;的前面。
            [self.tableView reloadData];    
            // 取消
            [self.tableView setEditing:YES animated:NO];
            // 全選
            self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.leftBarButtonItem];
        self.leftBarButtonItem.selected = NO;
        
            // show
            [self _showDeleteButton];
         }else{
             // 清空選中欄
            [self.selectedDatas removeAllObjects];
            // 編輯
            [self.tableView setEditing:NO animated:NO];
            // 返回
            self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:self.backBarButtonItem];
            // hide
            [self _hideDeleteButton];
        }
}
五、拓展
  1. 如果客戶想用系統自帶的多選功能,但是要改變選中按鈕的樣式。例如下圖所示:


    自定義樣式效果圖.gif
  2. 由于該選中圖片在界面上已經顯示出來了,那肯定是存在的。可以調用 [cell subviews]方法尋找。猜想可能是UIControl的子類。打印Cell的子控件如下圖所示: 由下圖不難看出,此時選中的cell中有四個子視圖類名分別為:UIViewUITableViewCellContentView_UITableViewSeparatorViewUITableViewCellEditControlUITableViewCellEditControl肯定是我們想要的,正好里面還有一個imageView屬性。但是查詢UITableViewCell的關于UITableViewCellEditControl的API,并未發現關于其的解釋,則利用KVC(key-value-coding)鍵值編碼,對OC這門動態語言量身定制,利用runtime運行時原理動態為對象設置屬性。

    cell子控件@2x.png

  3. 修改選中按鈕的樣式

/** 修改選中按鈕的樣式 */
 - (void)_changeCellSelectedImage
{
      // 利用KVC 設置color
      for (UIView *view in self.subviews) {
        
          if ([view isKindOfClass:[UIControl class]])
          {
              for (UIView *subview in view.subviews) {
                   if ([subview isKindOfClass:[UIImageView class]])
                   {
                        // MHGlobalOrangeTextColor :淺橙色
                        [subview setValue:MHGlobalOrangeTextColor forKey:@"tintColor"];
                    }
                }
            }
        }
 }
  1. 由于編輯狀態下點擊Cell,就得調用 - (void)_changeCellSelectedImage這個方法修改選中按鈕的樣式。以及長按Cell也得修改樣式,根據MVC設計模式的原則,自定義Cell,監聽Cell選中狀態高亮狀態,從而將業務邏輯屏蔽起來。
/** 選中cell的時候調用 */
  - (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
        // 非編輯狀態下 直接退出
        if (!self.isEditing) return;
        // 非修改系統選中圖標樣式
        if (!self.isModifySelectionStyle) return;
    
        // 修改系統選擇按鈕的樣式
        if (selected) {
            // 改變
            [self _changeCellSelectedImage];
        }
}
/** 長按cell高亮狀態下 */
 - (void) setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
        [super setHighlighted:highlighted animated:animated];
        // 非編輯狀態下 直接退出
        if (!self.isEditing) return;
        // 非修改系統選中圖標樣式
        if (!self.isModifySelectionStyle) return;
    
        if (highlighted) {
            // 改變
            [self _changeCellSelectedImage];
        }
}
  1. 編輯的情況下,Cell的選中狀態下高亮狀態都會調用- (void)_changeCellSelectedImage這個方法,但該方法內部是在遍歷Cell的子控件,若選中過于頻繁,則會占用一點內存(注:Cell的子控件只有四個,其實影響不大)。則需要利用緩存機制了。Demo中未做緩存處理。
五、期待
  1. 文章若對您有點幫助,請給個喜歡??;若沒啥幫助,請給點建議。
  2. 針對文章所述,您閱讀有什么疑問;或使用Demo中有什么bug。請在文章底部評論,我會盡快解決問題。
  3. GitHub地址:https://github.com/CoderMikeHe
六、代碼

MHDevelopExample_Objective_C - MHSelectsController.h/m

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容