iOS~ 自定义:cell左滑删除按钮样式、两种上下移动位置方法

一、左滑删除cell:

iOS tableView侧滑多按钮的处理

#pragma mark 左滑删除cell
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    if (self.oftenModels.count > 0) {
        // 类型: 1 :添加的球场 2:上次选择 3 :离我最近
        NSInteger type = self.oftenModels[indexPath.row].type;

        if (type == 1) {
                   
//            [self changeConfigSwipeButtons];
            
            //删除
            UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
                
                /**   点击 删除 按钮的操作 */
                if (self.deleteSelectCellBlock) {
                    self.deleteSelectCellBlock(YES, indexPath.row);
                }
            }];
            
            
            deleteRowAction.title = @"删除";
//            deleteRowAction.backgroundColor = RGBA(223, 109, 53, 1);
//            deleteRowAction.backgroundColor = [UIColor clearColor];
            
            UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteRowAction]];
            config.performsFirstActionWithFullSwipe = NO; // 禁止侧滑无线拉伸
            
            return config;
        } else {
            return nil;
        }
    } else {
        return nil;
    }
    
}

- (void)tableView:(UITableView *)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath {
//    NSLog(@"😭😭 == willBeginEditing");
    [self changeConfigSwipeButtons];
}

- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath {
//    NSLog(@"😆😆😆😆 == didEndEditing");
}


//- (void)layoutSubviews {
//    [super layoutSubviews];
////    [self changeConfigSwipeButtons];
//}

#pragma mark -- -- 自定义修改左滑 删除按钮 样式
- (void)changeConfigSwipeButtons {

    // iOS 11层级 : UITableView -> UISwipeActionPullView(当左滑出现“删除”按钮时,按钮的俯视图是UISwipeActionPullView)
    for (UIView *subview in self.tableView.subviews) {
         // ios 11以下
         if ([subview isKindOfClass:NSClassFromString(@"UISwipeActionPullView")] && [subview.subviews count] >= 1)
         {
              // 找到这个按钮之后
              UIButton*readButton = subview.subviews[0];
             // [readButton setImage:[UIImage imageNamed:@"plan_delete"] forState:UIControlStateNormal];

            // 直接创建一个UIImageView,放到上面,注意边距
            UIImageView *img = [[UIImageView alloc] init];
            img.image = [UIImage imageNamed:@"delete_City_icon"];
            [readButton addSubview:img];
            [img makeConstraints:^(MASConstraintMaker *make) {
                make.top.left.equalTo(readButton);
                make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*60);
                make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*100);
            }];
              break;
         }
        // ios 13
        // _UITableViewCellSwipeContainerView 是tableview 的子视图,UISwipeActionPullView是_UITableViewCellSwipeContainerView的子视图
         else if ([subview isKindOfClass:NSClassFromString(@"_UITableViewCellSwipeContainerView")] && [subview.subviews count] >= 1) {
             for (UIView *subview0 in subview.subviews){
                 if ([subview0 isKindOfClass:NSClassFromString(@"UISwipeActionPullView")] && [subview0.subviews count] >= 1){
                     
                     UIButton *deleteButton = subview0.subviews[0]; // 第一层视图
                     deleteButton.layer.backgroundColor = RGBA(223, 109, 53, 1).CGColor;
                    // 这个是将view转成image
                    // [deleteButton setBackgroundImage:[UIImage imageWithColor:UIColorFromHex(@"de6d3c") size:CGSizeMake(80, 135)] forState:UIControlStateNormal];
                     // 直接创建一个UIImageView,放到上面,注意边距

                    UIImageView *img = [[UIImageView alloc] init];
                    img.image = [UIImage imageNamed:@"delete_City_icon"];
                    [deleteButton addSubview:img];
                    [img makeConstraints:^(MASConstraintMaker *make) {
                        make.top.left.equalTo(deleteButton);
                        make.width.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*60);
                        make.height.mas_equalTo([UIScreen mainScreen].bounds.size.width/375*100);
                    }];
//                     deleteButton.backgroundColor = RGBA(223, 109, 53, 1);
//                     [deleteButton setTitle:@"删除" forState:UIControlStateNormal];
//                     [deleteButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
//                     deleteButton.titleLabel.font = [UIFont systemFontOfSize:[UIScreen mainScreen].bounds.size.width/375*16 weight:UIFontWeightMedium];
//                     deleteButton.layer.masksToBounds = YES;
//                     deleteButton.layer.cornerRadius = [UIScreen mainScreen].bounds.size.width/375*12;
//                     [deleteButton makeConstraints:^(MASConstraintMaker *make) {
//                         make.center.equalTo(subview0.subviews[0]);
//                         make.width.mas_equalTo(200);
//                         make.height.mas_equalTo(30);
//                     }];
                     
                     
                     //修改按钮-颜色
//                     UIButton *swipeActionStandardBtn = subview0.subviews[0];
//                     swipeActionStandardBtn.backgroundColor = RGBA(223, 109, 53, 1);
//                     swipeActionStandardBtn.layer.masksToBounds = YES;
//                     swipeActionStandardBtn.layer.cornerRadius = [UIScreen mainScreen].bounds.size.width/375*12;
//                     swipeActionStandardBtn.layer.maskedCorners = kCALayerMinXMinYCorner | kCALayerMinXMaxYCorner; // 设置某一个角(自动布局可用)
//                     swipeActionStandardBtn.clipsToBounds = YES; // 设置这个属性,子视图超出边界裁剪掉
//                     if ([swipeActionStandardBtn isKindOfClass:NSClassFromString(@"UISwipeActionStandardButton")]) {
//                             CGFloat swipeActionStandardBtnOX = swipeActionStandardBtn.frame.origin.x;
//                             CGFloat swipeActionStandardBtnW  = swipeActionStandardBtn.frame.size.width;
//                             swipeActionStandardBtn.frame = CGRectMake(swipeActionStandardBtnOX, 0, swipeActionStandardBtnW, 30);
//                     }
                     
                     
                     break;
                 }
             }
         }

    }
}

/**
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {
    if (!color || size.width <= 0 || size.height <= 0) return nil;
    CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, color.CGColor);
    CGContextFillRect(context, rect);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
*/

二、UITableView上下移动位置(系统):

1、第一种:不用drag和drop

代码

[self.tableView setEditing:YES animated:YES]; // 进入可编辑状态
//默认编辑模式下,每个cell左边有个红色的删除按钮,设置为None即可去掉
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewCellEditingStyleNone;
}

//是否允许indexPath的cell移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) {
        return NO;
    } else {
        return YES;
    }
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    
    
    NSMutableArray *dataArray = [NSMutableArray arrayWithCapacity:0];
//    dataArray = [self.listModels mutableCopy];
//
//    // 当结束移动时,判断结束时的位置,把移动的元素删除再加到结束的位置
//    if (sourceIndexPath.row < self.listModels.count) {
//
//        GWCityManageListModel *userModel = self.listModels[sourceIndexPath.row];
//        [dataArray removeObjectAtIndex:sourceIndexPath.row];
//
//        if (destinationIndexPath.row >= dataArray.count) {
//            [dataArray addObject:userModel];
//        } else {
//            [dataArray insertObject:userModel atIndex:destinationIndexPath.row];
//        }
//
//    }
//    self.listModels  = [dataArray copy];
//
//    // 改变保存的值
//    [[NSUserDefaults standardUserDefaults] setObject:self.listModels forKey:@"saveSort_CityManage_CityWeather_Arr"];
    
    
    NSLog(@"移动的位置索引 = %ld,\n 将要移动到达的位置索引 == %ld", sourceIndexPath.row, destinationIndexPath.row);
    //更新数据源
}

#pragma mark -- 禁止某一行移动
// 禁止某一行移动,并且禁止其他cell移动到该cell的索引位置(这里禁止移动第一行)
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
    
    NSIndexPath *indexPath = nil;
    
    // 要求:第一个cell位置置顶,不可移动,所以当移动其他cell到该位置时,进行下列操作:
    if (proposedDestinationIndexPath.row == 0) {
        indexPath = [NSIndexPath indexPathForRow: 1 inSection: 0];
    } else {
        indexPath = [NSIndexPath indexPathForRow: proposedDestinationIndexPath.row inSection: 0];
    }
    return indexPath;
}

2、第二种,使用 drag和drop
需要遵守和实现UITableViewDragDelegate和UITableViewDropDelegate代理和其代理方法:

在UITableView中,我们可以使用- (BOOL) tableView: (UITableView *) tableView canMoveRowAtIndexPath: (NSIndexPath *) indexPath方法来禁止移动某一行。下面的例子是禁止移动最后一行。但是,虽然不能移动最后一行,却可以将其他行移动至最后一行下方。
所以需要方法:- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;来设置。
遵守协议:

    <UITableViewDragDelegate, UITableViewDropDelegate>
//    [self.tableView setEditing:YES animated:YES]; // 进入可编辑状态
    self.tableView.dragDelegate = self; // drag 拖拉代理
    self.tableView.dropDelegate = self; // drop
    self.tableView.dragInteractionEnabled = YES; // 打开拖拽功能
    _tableView = [[UITableView alloc] initWithFrame:CGRectMake([UIScreen mainScreen].bounds.size.width/375*20, [UIScreen mainScreen].bounds.size.width/375*15, [UIScreen mainScreen].bounds.size.width/375*335, [UIScreen mainScreen].bounds.size.height - k_Height_StatusBar - k_Height_NavContentBar - [UIScreen mainScreen].bounds.size.width/375*(75 + 15)) style:UITableViewStyleGrouped];
    self.tableView.backgroundColor = RGBA(248, 249, 250, 1);
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.tableView.dragDelegate = self; // drag 拖拉代理
    self.tableView.dropDelegate = self; // drop
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    [self.backView addSubview:self.tableView];
//默认编辑模式下,每个cell左边有个红色的删除按钮,设置为None即可去掉
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
    return UITableViewCellEditingStyleNone;
}

//是否允许indexPath的cell移动
//是否允许indexPath的cell移动
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    if (indexPath.row == 0) { // 禁止第一行移动
        return NO;
    } else {
        return YES;
    }
}

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath {
    
    
    NSMutableArray *dataArray = [NSMutableArray arrayWithCapacity:0];
    dataArray = [self.listModels mutableCopy];
    
    // 当结束移动时,判断结束时的位置,把移动的元素删除再加到结束的位置
    if (sourceIndexPath.row < self.listModels.count) {
        
        GWCityManageListModel *userModel = self.listModels[sourceIndexPath.row];
        [dataArray removeObjectAtIndex:sourceIndexPath.row];
        
        if (destinationIndexPath.row >= dataArray.count) {
            [dataArray addObject:userModel];
        } else {
            [dataArray insertObject:userModel atIndex:destinationIndexPath.row];
        }
        
    }
    self.listModels  = [dataArray copy];
    
    
    /**
     连续使用交换位置方法:exchangeObjectAtIndex,
     
    例子: 当前index和index+1交换,一直交换到目标位置
    数组:12345,21345,23145,23415,23451
    移动“1”的位置,前移就是减(index-1),后移就是加(index+1)
     
     // 交换位置:exchangeObjectAtIndex,在这里不使用
     [dataArray exchangeObjectAtIndex:destinationIndexPath.row withObjectAtIndex:sourceIndexPath.row];
     */
    
    
//    // 从数组中读取需要移动行的数据
//    id  object = [dataArray objectAtIndex:fromRow];
//    // 在数组中移动需要移动的行的数据
//    [dataArray removeObjectAtIndex:fromRow];
//    // 把需要移动的单元格数据在数组中,移动到想要移动的数据前面
//    [dataArray insertObject:object atIndex:toRow];
    
    NSLog(@"移动的位置索引 = %ld,\n 将要移动到达的位置索引 == %ld", sourceIndexPath.row, destinationIndexPath.row);
    //更新数据源
}

#pragma mark -- 禁止某一行移动
// 禁止某一行移动,并且禁止其他cell移动到该cell的索引位置(这里禁止移动第一行)
- (NSIndexPath *)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath {
    
    NSIndexPath *indexPath = nil;
    
    // 要求:第一个cell位置置顶,不可移动,所以当移动其他cell到该位置时,进行下列操作:
    if (proposedDestinationIndexPath.row == 0) {
        indexPath = [NSIndexPath indexPathForRow: 1 inSection: 0];
    } else {
        indexPath = [NSIndexPath indexPathForRow:proposedDestinationIndexPath.row inSection: 0];
    }
    return indexPath;
}

#pragma mark -- <UITableViewDragDelegate>

// 拖拽 预览
- (nullable UIDragPreviewParameters *)tableView:(UITableView *)tableView dragPreviewParametersForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    // 可以在该方法内使用 贝塞尔曲线 对单元格的一个具体区域进行裁剪
    UIDragPreviewParameters *parameters = [[UIDragPreviewParameters alloc] init];

    CGRect rect = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width/375*(375 - 48), [UIScreen mainScreen].bounds.size.width/375*(100));
    parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:[UIScreen mainScreen].bounds.size.width/375*16];
    parameters.backgroundColor = RGBA(248, 249, 250, 0.3);
    return parameters;
}

- (void)tableView:(UITableView *)tableView dragSessionWillBegin:(id<UIDragSession>)session {
    // 将要 拖拽
    NSLog(@"😁😆");
}

- (void)tableView:(UITableView *)tableView dragSessionDidEnd:(id<UIDragSession>)session {
    // 拖拽 结束
    NSLog(@"😁😆");
}

/**
 当接收到添加item响应时,会调用该方法向已经存在的drag会话中添加item
 如果需要,可以使用提供的点(在集合视图的坐标空间中)进行其他命中测试。
 如果该方法未实现,或返回空数组,则不会将任何 item 添加到拖动,手势也会正常的响应
 */
- (nonnull NSArray<UIDragItem *> *)tableView:(nonnull UITableView *)tableView itemsForBeginningDragSession:(nonnull id<UIDragSession>)session atIndexPath:(nonnull NSIndexPath *)indexPath {
    return nil;
//    return @[[[UIDragItem alloc] initWithItemProvider:[NSItemProvider new]]];
    
//    NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithObject:self.dataSource[indexPath.item]];
//    UIDragItem *item = [[UIDragItem alloc] initWithItemProvider:itemProvider];
//    return @[item];
}

// 确保实现该UITableViewDragDelegate方法,并返回YES。这将确保拖放必须发生在同一个应用程序中。
- (BOOL)tableView:(UITableView *)tableView dragSessionIsRestrictedToDraggingApplication:(id<UIDragSession>)session {
    return YES;
}

#pragma mark -- <UITableViewDropDelegate>
// 松手 预览
- (nullable UIDragPreviewParameters *)tableView:(UITableView *)tableView dropPreviewParametersForRowAtIndexPath:(NSIndexPath *)indexPath {
    
    // 可以在该方法内使用 贝塞尔曲线 对单元格的一个具体区域进行裁剪
    UIDragPreviewParameters *parameters = [[UIDragPreviewParameters alloc] init];
    
    CGRect rect = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width/375*(375 - 48), [UIScreen mainScreen].bounds.size.width/375*(100));
    parameters.visiblePath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:[UIScreen mainScreen].bounds.size.width/375*16];
    parameters.backgroundColor = RGBA(248, 249, 250, 0.3);
    return parameters;
}

- (void)tableView:(UITableView *)tableView dropSessionDidExit:(id<UIDropSession>)session {
    
}

- (void)tableView:(UITableView *)tableView dropSessionDidEnd:(id<UIDropSession>)session {
    
}

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

推荐阅读更多精彩内容