欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

iOS自定义UITableViewRowAction

程序员文章站 2022-03-11 10:12:46
...

先看效果 :

iOS自定义UITableViewRowAction

iOS自定义UITableViewRowAction

 

说下思路:首先要实现tableview的代理。共有几个方法:

1:

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
    return YES;
}

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

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
    WEAK_SELF;
    UITableViewRowAction *deleteRowAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"删除"handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
        NSLog(@"点击了删除");
        [tableView setEditing:NO animated:YES];
        AddressRecord *record = weakSelf.addressArray[indexPath.row];
        [weakSelf deleteAddress:record.id];
    }];
    deleteRowAction.backgroundColor = ColorRGB(83, 80, 84);
    
    UITableViewRowAction *setDefaultAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"设置默认"handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
        AddressRecord *record = weakSelf.addressArray[indexPath.row];
        [tableView setEditing:NO animated:YES];
        [weakSelf setDefaultAddress:record.id];
    }];
    setDefaultAction.backgroundColor = ColorRGB(169, 166, 170);
    AddressRecord *record = self.addressArray[indexPath.row];
    if (record.is_default) {
        return @[deleteRowAction];
    }else{
        return @[deleteRowAction,setDefaultAction];
    }
}

以上几个方法能看懂什么意思就不说了  调用这几个方法就能实现侧滑出现自定义button

在iOS11以上。新增了一个方法:

- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath  API_AVAILABLE(ios(11.0)){
    WEAK_SELF;
    if (@available(iOS 11.0, *)) {
        UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
            AddressRecord *record = weakSelf.addressArray[indexPath.row];
            [weakSelf deleteAddress:record.id];
        }];

        UIContextualAction *editRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:@"设置默认" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
            AddressRecord *record = weakSelf.addressArray[indexPath.row];
            [tableView setEditing:NO animated:YES];
            [weakSelf setDefaultAddress:record.id];
        }];
        AddressRecord *record = self.addressArray[indexPath.row];
        if (record.is_default) {
            UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteRowAction]];
            //设置全屏滑动时不自定响应事件
            config.performsFirstActionWithFullSwipe = false;
            return config;
        }else{
            UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteRowAction,editRowAction]];
            //设置全屏滑动时不自定响应事件
            config.performsFirstActionWithFullSwipe = false;
            return config;
        }
    }else{
        return nil;
    }
}

 

这个方法的实现看起来有点熟悉,在iOS11以上的系统中测试的时候用力向左侧滑会发现一个问题,侧滑之后会自动执行第一个action的事件,你没有点击那个action却执行了方法,比如我的demo中最右的action是删除  那么我测试的时候用力左滑之后会自动删除掉当前cell  我以为出bug了。后来查资料看到了这个方法,在iOS11以上的系统实现这个方法可以禁用掉左滑事件。同时自定义action的事件。由于里面的代码跟上面第一步的代理的action的代码一样,所以有些重复,不过能很好的解决这个bug。

 

3:剩下的就很简单了,在controller中侧滑事件发生后会触发代理:


- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
    [self.view setNeedsLayout];
}

在这个代理中让self。view刷新UI,重绘,然后就会调用系统方法:

- (void)viewDidLayoutSubviews{
    [super viewDidLayoutSubviews];
    [self configSwipeButtons];
}

configSwipeButtons方法中就是对tableview进行遍历,找到action上面的各个button,对其进行自定义操作就可以。

4:说明:在iOS13和iOS11和iOS10以下这三部分系统,action所在的table的层级和名称是不一样的,所以要加以区分:

- (void)configSwipeButtons{
    if (@available(iOS 13.0, *)) {
        for (UIView *subview in self.tableView.subviews){
            if ([subview isKindOfClass:NSClassFromString(@"_UITableViewCellSwipeContainerView")] ){
                for (UIView *actionView in subview.subviews) {
                    if ([actionView isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]) {
                        actionView.backgroundColor = COLOR(clearColor);
                        if (actionView.subviews.count >= 2) {
                            UIButton *deleteButton = actionView.subviews[1];
                            UIButton *readButton = actionView.subviews[0];
                            [self configDeleteButton:deleteButton];
                            [self configReadButton:readButton];
                        }else if (actionView.subviews.count <2){
                            UIButton *deleteButton = actionView.subviews[0];
                            [self configDeleteButton:deleteButton];
                        }
                    }
                }
            }
        }
    }else if (@available(iOS 11.0, *)){
        // iOS 11层级 (Xcode 8编译): UITableView -> UITableViewWrapperView -> UISwipeActionPullView
        for (UIView *subview in self.tableView.subviews){
            if ([subview isKindOfClass:NSClassFromString(@"UITableViewWrapperView")]){
                for (UIView *actionView in subview.subviews){
                    if ([actionView isKindOfClass:NSClassFromString(@"UISwipeActionPullView")]){
                        actionView.backgroundColor = COLOR(clearColor);
                        if (actionView.subviews.count >= 2) {
                            UIButton *deleteButton = actionView.subviews[1];
                            UIButton *readButton = actionView.subviews[0];
                            [self configDeleteButton:deleteButton];
                            [self configReadButton:readButton];
                        }else if (actionView.subviews.count <2){
                            UIButton *deleteButton = actionView.subviews[0];
                            [self configDeleteButton:deleteButton];
                        }
                    }
                }
            }
        }
    }else{
        // iOS 8-10层级: UITableView -> UITableViewCell -> UITableViewCellDeleteConfirmationView
        AddressTableViewCell *tableCell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
        for (UIView *subview in tableCell.subviews){
            if ([subview isKindOfClass:NSClassFromString(@"UITableViewCellDeleteConfirmationView")] && [subview.subviews count] >= 2){
                UIButton *deleteButton = subview.subviews[0];
                UIButton *readButton = subview.subviews[1];
                [self configDeleteButton:deleteButton];
                [self configReadButton:readButton];
            }
        }
    }
}

- (void)configDeleteButton:(UIButton*)deleteButton{
    deleteButton.titleLabel.font = FONT_Regular(13);
    [deleteButton setTitleColor:COLOR(whiteColor) forState:0];
    [deleteButton setBackgroundImage:[UIImage imageWithColor:ColorRGB(80, 83, 86)] forState:0];
    deleteButton.layer.cornerRadius = 10;
    deleteButton.layer.masksToBounds = YES;
    [deleteButton updateConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(W(65));
        make.top.equalTo(H(10));
        make.bottom.equalTo(-1);
    }];
}

- (void)configReadButton:(UIButton*)readButton{
    readButton.titleLabel.font = FONT_Regular(13);
    [readButton setTitleColor:COLOR(whiteColor) forState:0];
    [readButton setBackgroundImage:[UIImage imageWithColor:ColorRGB(169, 166, 170)] forState:0];
    readButton.layer.cornerRadius = 10;
    readButton.layer.masksToBounds = YES;
    [readButton updateConstraints:^(MASConstraintMaker *make) {
        make.width.equalTo(W(65));
        make.top.equalTo(H(10));
        make.bottom.equalTo(-1);
    }];
}

到此为止,大功告成