如何在UIContextMenu的previewView上添加按钮并启用点击交互
解决方案
核心原因:仅设置UserInteractionEnabled无效是因为系统默认在预览视图上添加了高优先级的点击手势,点击后会直接触发上下文菜单收起,同时拦截视图内部子控件的交互。
iOS 16+ 最简方案
iOS 16 新增了interactivePreviewEnabled配置项,直接开启即可允许预览视图内部交互,不会默认点击收起:
- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location { UIContextMenuConfiguration *config = [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:^UIViewController * _Nullable{ // 返回你的自定义预览控制器,按钮直接添加在该控制器的view上 CustomPreviewViewController *previewVC = [[CustomPreviewViewController alloc] init]; previewVC.preferredContentSize = CGSizeMake(300, 150); // 按需设置预览大小 return previewVC; } actionProvider:^UIMenu * _Nullable(NSArray<UIMenuElement *> * _Nonnull suggestedActions) { // 你的上下文菜单选项配置 return [UIMenu menuWithChildren:suggestedActions]; }]; // 关键:开启交互式预览 if (@available(iOS 16.0, *)) { config.interactivePreviewEnabled = YES; } return config; } // 空实现该方法,禁用点击预览默认跳转/收起行为 - (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionCommitAnimating>)animator { }
iOS 14~15 兼容方案
低版本系统没有官方API支持,可通过拦截系统默认手势实现:
// 菜单弹出时获取系统添加的点击手势 - (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willDisplayMenuForConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionAnimating>)animator API_AVAILABLE(ios(14.0)) { UIPreviewPresentationController *previewPresentationController = interaction.presentingViewController.presentedViewController.previewPresentationController; for (UIGestureRecognizer *ges in previewPresentationController.view.gestureRecognizers) { if ([ges isKindOfClass:[UITapGestureRecognizer class]]) { ges.delegate = self; } } } // 实现手势代理,拦截按钮区域的点击事件不触发系统收起 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { // 判断点击位置是否为预览内的按钮,按需调整判断逻辑 if ([touch.view isKindOfClass:[UIButton class]]) { return NO; } return YES; }
注意事项
- 不要使用系统默认生成的预览视图,必须通过
previewProvider返回自定义的预览控制器,子控件交互才会生效 - 按钮的点击事件正常添加到自定义预览控制器内即可触发
- 你需要添加按钮的红色区域位置参考如下:

内容的提问来源于stack exchange,提问作者abhimuralidharan
相关产品推荐
相关产品推荐

