iOS开发:如何为UITableView实现多行选中的ContextMenu功能?
UITableView 多行选中上下文菜单实现方案
UITableView 确实没有像 UICollectionView(iOS 16+)那样原生提供多行选中的上下文菜单方法,但可以通过以下两种方式实现类似「文件」App 的交互效果:
方法一:自定义长按手势 + 多选模式
通过手动添加长按手势,在触发时判断选中行数,手动生成上下文菜单。
- 开启 UITableView 多选模式
self.tableView.allowsMultipleSelection = YES;
- 添加自定义长按手势并处理逻辑
// 初始化并添加长按手势 - (void)viewDidLoad { [super viewDidLoad]; UILongPressGestureRecognizer *multiSelectLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleMultiSelectLongPress:)]; multiSelectLongPress.minimumPressDuration = 0.5; [self.tableView addGestureRecognizer:multiSelectLongPress]; } // 处理长按手势 - (void)handleMultiSelectLongPress:(UILongPressGestureRecognizer *)gesture { if (gesture.state != UIGestureRecognizerStateBegan) return; NSArray<NSIndexPath *> *selectedPaths = self.tableView.indexPathsForSelectedRows; // 仅当选中行数大于1时展示多行菜单 if (selectedPaths.count <= 1) return; CGPoint triggerPoint = [gesture locationInView:self.tableView]; UIContextMenuConfiguration *menuConfig = [self buildMultiSelectMenuForPaths:selectedPaths]; if (menuConfig) { UIContextMenuInteraction *interaction = [[UIContextMenuInteraction alloc] initWithDelegate:self]; [self.tableView addInteraction:interaction]; [interaction presentMenuAtLocation:triggerPoint inView:self.tableView animated:YES]; } } // 构建多行选中菜单 - (UIContextMenuConfiguration *)buildMultiSelectMenuForPaths:(NSArray<NSIndexPath *> *)indexPaths { return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) { // 批量删除操作 UIAction *deleteAction = [UIAction actionWithTitle:@"批量删除" image:[UIImage systemImageNamed:@"trash"] identifier:nil handler:^(UIAction * _Nonnull action) { [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic]; }]; // 批量分享操作 UIAction *shareAction = [UIAction actionWithTitle:@"批量分享" image:[UIImage systemImageNamed:@"square.and.arrow.up"] identifier:nil handler:^(UIAction * _Nonnull action) { // 实现分享逻辑 }]; return [UIMenu menuWithTitle:@"批量操作" children:@[deleteAction, shareAction]]; }]; }
方法二:拦截原生单行菜单,判断选中行数
利用原生的单行上下文菜单方法,在触发时检测当前选中行数,动态切换菜单内容。
- (nullable UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point { NSArray<NSIndexPath *> *selectedPaths = tableView.indexPathsForSelectedRows; // 多行选中时返回批量操作菜单 if (selectedPaths.count > 1) { return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) { UIAction *batchDeleteAction = [UIAction actionWithTitle:@"批量删除" image:[UIImage systemImageNamed:@"trash"] identifier:nil handler:^(UIAction * _Nonnull action) { [tableView deleteRowsAtIndexPaths:selectedPaths withRowAnimation:UITableViewRowAnimationAutomatic]; }]; return [UIMenu menuWithTitle:@"批量操作" children:@[batchDeleteAction]]; }]; } // 单行选中时返回常规操作菜单 else { return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil actionProvider:^UIMenu * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) { UIAction *editAction = [UIAction actionWithTitle:@"编辑" image:[UIImage systemImageNamed:@"pencil"] identifier:nil handler:^(UIAction * _Nonnull action) { // 实现单行编辑逻辑 }]; return [UIMenu menuWithTitle:@"操作" children:@[editAction]]; }]; } }
注意事项
- 两种方案都需要将
tableView.allowsMultipleSelection设置为YES,且仅支持 iOS 13 及以上系统(ContextMenu 最低兼容版本)。 - 方法一更贴近「文件」App 的交互流程:先选中多行,再长按触发菜单;方法二是长按已选中的多行时直接替换菜单内容。
内容的提问来源于stack exchange,提问作者MACV
相关产品推荐
相关产品推荐

