UITableView 编辑模式详解

作者: 秋刀生鱼片 | 来源:发表于2015-12-24 11:20 被阅读14647次

    UITableView 编辑模式详解

    UITableView的相关编辑操作非常全,今天我们来做一个总结。跟编辑相关的属性和接口有如下,我们一个一个分析,我们先认真阅读一下相关头文件,我根据意思大概翻译了一下注释。

    属性方法

    @property (nonatomic, getter=isEditing) BOOL editing;                             
    // 默认状态是非编辑状态,如果不调用下面接口直接设置,是没有动画的
    - (void)setEditing:(BOOL)editing animated:(BOOL)animated;
    

    DataSource

    // 当增减按钮按下时,用来处理数据和UI的回调。
    // 8.0版本后加入的UITableViewRowAction不在这个回调的控制范围内,UITableViewRowAction有单独的回调Block。
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 这个回调实现了以后,就会出现更换位置的按钮,回调本身用来处理更换位置后的数据交换。
    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
    
    // 这个回调决定了在当前indexPath的Cell是否可以编辑。
    - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 这个回调决定了在当前indexPath的Cell是否可以移动。
    - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
    

    Delegate

    // 这个回调很关键,返回Cell的编辑样式。
    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 删除按钮的文字
    - (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;
    
    // 8.0后侧滑菜单的新接口,支持多个侧滑按钮。
    - (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;
    
    // 这个接口决定编辑状态下的Cell是否需要缩进。
    - (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
    
    // 这是两个状态回调
    - (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
    - (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
    

    编辑状态

    UITableView通过editing属性控制编辑状态,调用- (void)setEditing:(BOOL)editing animated:(BOOL)animated接口,可以决定是否使用原生的变换动画。

    当调用这个接口,并将editing设为YES是,UITableView将开始询问代理(Delegate)需要编辑哪些Cell,用什么样的方式编辑。

    首先调用回调方法- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;,这里需要返回YES;

    然后依次为各个Cell调用- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;方法获取编辑样式。

    typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
        UITableViewCellEditingStyleNone,
        UITableViewCellEditingStyleDelete,
        UITableViewCellEditingStyleInsert
    };
    

    编辑样式枚举有三种,位运算组合则由不同的用途。

    UITableViewCellEditingStyleNone 没有编辑样式
    UITableViewCellEditingStyleDelete 删除样式 (左边是红色减号)
    UITableViewCellEditingStyleInsert 插入样式  (左边是绿色加号)
    UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert 多选模式,左边是蓝色对号
    

    特别注意,右边的移动并不是这里控制的,需要实现下面这个回调才会出现。

    - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
    

    另外对于新手来说,要明白这里的回调都没有对UI和数据进行操作,开发者需要在回调中,完成相应的操作。比如删除或者添加一条数据,应在

    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
    

    上面这个回调中,根据editingStyle进行判断,处理对应的UI和数据。

    数据与UI更新

    数据更新没什么好说的,直接操作数据容器就好,无论是数组、字典还是CoreData数据。UI更新则需要使用TableView的方法,如果需求reloadData无法满足,则必须使用下面的方法

    - (void)beginUpdates;   // allow multiple insert/delete of rows and sections to be animated simultaneously. Nestable
    - (void)endUpdates;     // only call insert/delete/reload calls or change the editing state inside an update block.  otherwise things like row count, etc. may be invalid.
    
    - (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
    - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
    - (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
    - (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);
    
    - (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    - (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
    - (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
    - (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);
    

    beginUpdatesendUpdates两个方法,在你需要批量处理Cell的时候,用来包裹住你的处理代码,其他方法名字都很直观,不一一介绍了。

    最后给大家推荐一个Cocoa框架里的功能强大的类NSFetchedResultsController,用于绑定CoreData数据和UITableView或者UICollectionView,直接封装好所有的UI操作代码,只要数据有变动,UI自动更新,爽的不要不要的,妈妈再也不用担心我的TableView写不好了,下一篇文章我准备详细讲一讲这个有趣的类。

    2017.11.29更新

    感谢简单程序媛同学的发问,在此补充一个回调,用于只使用tableView右侧排序功能,而不显示左侧删除和插入,并且左侧不留白的方法

    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
        return UITableViewCellEditingStyleNone; 
    }
    
    - (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
        return NO;
    }
    

    UITableViewCellEditingStyleNone隐藏了左侧编辑按钮,shouldIndentWhileEditingRowAtIndexPath控制cell在编辑模式下左侧是否缩进。

    相关文章

      网友评论

      • a7a5baaa2b04:请问下 怎么自定义cell右边移动的距离呢
        a7a5baaa2b04:我使用了这个-(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath 但依然没有效果
      • 若幹年後:小伙子 解决了我的一个问题 谢谢
        秋刀生鱼片:@若幹年後 不客气
      • 大林宝子:多选编辑模式下,不断刷新cell,如何保持cell选中状态
        Beyond无状态:@秋刀生鱼片 楼主 没明白啊 这种情况下是不是不能reloadData
        大林宝子:@秋刀生鱼片 3q
        秋刀生鱼片:cell 的 刷新回调中,
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
        根据tableiview的 [tableView indexPathsForSelectedRows] 返回的数组进行 设置。
      • coder袁:大神 。为什么我的左侧删除按钮怎么设置都出不来
        秋刀生鱼片:左侧删除是在tableview进入编辑模式才能出现的
        检查一下 【tableview isEditing】
      • 简单程序媛:我只需要cell右边的移动,但是进入编辑模式之后,虽然editingStyleForRowAtIndexPath这个方法我返回的是none,但是依然左侧会有一段距离空白,楼主有没有处理过这种情况?或者有没有方法可以处理掉这种情况的?
        秋刀生鱼片:@简单程序媛 不客气 (:
        简单程序媛:@秋刀生鱼片 真的解决了,谢谢楼主!一开始我是设置左边的label距离左边为-25的约束,这样也算解决了我的问题,但是感觉好low。所以非常感谢你提供的方法,谢谢!
        秋刀生鱼片:我还真遇到过这个情况

        当时没有研究,下面是我在stackoverflow找到的解决办法

        ```
        - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
        return UITableViewCellEditingStyleNone;
        }

        - (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
        return NO;
        }
        ```

        你试试
      • 方向_4d0d:没有具体看到您的下一篇啊
        秋刀生鱼片:@方向_4d0d 暂时没有~
        方向_4d0d:@秋刀生鱼片 可以 UISearchBar有关的有吗
        秋刀生鱼片:@方向_4d0d http://www.jianshu.com/p/57aca4e892fe
        这个。
      • 睿少:为什么我进入编辑模式后,cell不向右移动,出现的删除按钮回覆盖cell上的控件,求助大神!!
        秋刀生鱼片:@睿少 不客气
        睿少:@秋刀生鱼片 嗯嗯,没有添加到contentView!谢谢!
        秋刀生鱼片:有两种可能性。
        1. view没有添加到 cell的contentView上,而是直接加在cell上了
        2. 使用了第三方派生cell

      • 谢谢生活:有没有Demo,谢谢楼主分享
        秋刀生鱼片:@谢谢生活 木。有。 (o.O)~
      • TeacherXue:好文好文

      本文标题:UITableView 编辑模式详解

      本文链接:https://www.haomeiwen.com/subject/dopvhttx.html