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);
    }];
}

到此爲止,大功告成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章