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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容