美文网首页实用工具
iOS UITableView左滑操作功能的实现(iOS8-11

iOS UITableView左滑操作功能的实现(iOS8-11

作者: sonialiu | 来源:发表于2018-02-08 10:48 被阅读424次

    该文同时发表在腾讯WeTest公众号:iOS UITableView左滑操作功能的实现(iOS8-11) 欢迎点击阅读

    本文主要是介绍下iOS 11系统及iOS 11之前的系统在实现左滑操作功能上的区别,及如何自定义左滑的标题颜色、字体

    1、左滑操作功能实现

    1.1 如果左滑的时候只有一个操作按钮,可以使用如下三个delegate方法来实现:

    //editing style
    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
        return UITableViewCellEditingStyleDelete;
    }
    //设置滑动cell出现的button标题,默认是"delete"
    - (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath {
        return @"删除";//or @"置顶"
    }
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
     //点击按钮后的操作
    }
    

    1.2 如果左滑有一个或多个操作按钮,iOS8-10 可使用如下两个delegate方法:

    //如果tableView中的每一行都可以进行左滑操作,该方法可不实现
    //If not implemented, all editable cells will have UITableViewCellEditingStyleDelete
    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        if (indexPath.section == FMMineCollectionSection_AlbumItems) {
            return UITableViewCellEditingStyleDelete;
        }
        return UITableViewCellEditingStyleNone;
    }
    
    // 必须写的方法(否则iOS 8无法删除,iOS 9及其以上不写没问题),和editActionsForRowAtIndexPath配对使用,里面什么不写也行
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    
    }
    
    //从iOS11开始该方法被废弃
    - (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
    {
       UITableViewRowAction *topRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"置顶" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
            //操作按钮点击的操作    
           }];
       topRowAction.backgroundColor = KE_COLOR(@"BT3");
       topRowAction.title = @"置顶";
      
        UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"点击了删除");
    }];
       return @[topRowAction, deleteRowAction];
      }
    }
    

    1.3 iOS 11之后,tableView的delegate增加了两个方法,用来取代editActionsForRowAtIndexPath方法,如下:

    // Swipe actions
    // These methods supersede -editActionsForRowAtIndexPath: if implemented
    // return nil to get the default swipe actions
    - ( UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
    
        UIContextualAction *topRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"置顶" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        NSLog(@"点击了置顶");
    }];
    
        UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        NSLog(@"点击了删除");
    }];
    
        UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[topRowAction,deleteRowAction]];
        return config;
    }
    

    在1.2和1.3中,如果是需要适配iOS 11之前的版本,以上三个方法都需要实现。

    1.4 上面1.2和1.3中实现的方法的区别

    体验上的不同就是当左滑只有一个button时,iOS 11中可以一直左滑,滑到一定程度时,会执行点击按钮的操作,iOS 11之前的不会。

    iOS 11之前如果想增大button区域,可通过在标题前后加空格的方式,但iOS 11不行,加空格无效,button大小固定,超过4个字时换行显示。

    2、左滑操作自定义标题颜色、字体

    因为系统对左滑出的按钮只提供了3个可设置的属性:title、backgroundColor、image,如果使用自定义的titleColor和font,就需要自己来实现了。实现的思想是hook系统实现,但鉴于UITableView的view层级结构在iOS 11中有所改变,所以iOS8-10和iOS11的实现有所不同,以下分别给出。

    考虑到代码的可复用性,自定义左滑操作的字体大小和颜色的代码不写在viewController中,而是写在UITableViewUITableViewCellCategory中,对外提供editActionTitleColoreditActionTitleFont属性来设置颜色和大小,需要使用自定义颜色和字体时只需要设置一下这两个属性即可。

    2.1 iOS 8-10 设置标题颜色和字体

    左滑操作后,UITableView的层级结构如下图:

    iOS8-10层级结构.png

    由上图可知,左滑的操作按钮是在UITableViewCell的子view,所以我们可以在UITableViewCellcategory中hook掉layoutSubviews方法,找到UITableViewCellDeleteConfirmationView的子view button,设置字体颜色和大小。

    代码如下:

    - (void)applyEditActionButtonStyle
    {
        if (self.editActionTitleColor) {//设置editActionTitleFont同理
            UIButton *btn = [self __findSwipActionButton];
            [btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
        }
    }
    
    - (UIButton *)__findSwipActionButton{
        if (![Common iOS11]) {
            UIView *extView = (UIView *)[self findSubviewOfTest:@"UITableViewCellDeleteConfirmationView" resursion:YES];
            for (UIButton *btn in extView.subviews) {
                if ([btn isKindOfClass:[UIButton class]]) {
                 return btn;
                }
            }
        }
        return nil;
    }
    

    2.2 iOS 11 设置标题颜色和字体

    左滑操作后,UITableView的层级结构如下图: iOS11 View的层级结构.png

    由上图可知,左滑的操作按钮是在UITableView的子view,所以我们可以在UITableViewcategory中hook掉layoutSubviews方法,找到UISwipeActionPullView的子view button,设置字体颜色和大小。

    代码如下:

    - (void)applyEditActionButtonStyle
    {
        if (self.editActionTitleColor) {//设置editActionTitleFont同理
            NSArray *btns = [self __findSwipActionButtons];
            for (UIButton *btn in btns) {
                [btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
            }
        }
    }
    
    - (NSArray<UIButton *> *)__findSwipActionButtons{
        if ([Common iOS11]) {
            NSMutableArray *buttons = [NSMutableArray array];
            for (UIView *extView in self.subviews) {
                if ([NSStringFromClass(extView.class) isEqualToString:@"UISwipeActionPullView"]) {
                    for (UIButton *btn in extView.subviews) {
                        if ([btn isKindOfClass:[UIButton class]]) {
                            [buttons addObject:btn];//要返回所有的左滑出的button
                        }
                    }
                }
            }
            return [buttons copy];
        }
        return nil;
    }
    

    3、遇到的问题及原因分析

    3.1 问题是iOS 11上设置颜色有延迟,颜色有一个明显的跳变,从系统默认色跳转到我设置的颜色

    有问题的代码如下:

    - (void)applyEditActionButtonStyle
    {
        if (self.editActionTitleColor) {
            UIButton *btn = [self __findSwipActionButton];
            [btn setTitleColor:self.editActionTitleColor forState:UIControlStateNormal];
        }
    }
    
    - (UIButton *)__findSwipActionButton{
    if ([Common iOS11]) {
        for (UIView *extView in self.subviews) {
            if ([NSStringFromClass(extView.class) isEqualToString:@"UISwipeActionPullView"]) {
                for (UIButton *btn in extView.subviews) {
                    if ([btn isKindOfClass:[UIButton class]]) {
                            return btn;
                        }
                    }
                }
            }
        }
        return nil;
    }
    

    3.2 问题原因分析

    当左滑一个cell后,直接操作左滑另一个cell,这个时候tableView上会有两个UISwipeActionPullView,此时tableView的部分view层级如下图所示:

    two_swipeActionView.png

    而上面的代码,在__findSwipActionButton方法中,找到其中一个UISwipeActionPullView上面的button就直接返回了,没有设置第二个UISwipeActionPullView的button的颜色,导致显示了系统默认色。

    3.3 解决方法

    将以上有问题的代码修改为以下代码:找出所有的UISwipeActionPullView,返回UISwipeActionPullView的button数组,对button数组进行设置字体颜色和大小,这个数组最多有两个元素,因为左滑出下一个cell时,上一个cell会逐渐消失,当此cell左滑操作完成时,上一个左滑的cell也会完成消失。

    解决后的代码如2.2的示例代码。

    相关文章

      网友评论

        本文标题:iOS UITableView左滑操作功能的实现(iOS8-11

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