You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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返回自定义的预览控制器,子控件交互才会生效
  • 按钮的点击事件正常添加到自定义预览控制器内即可触发
  • 你需要添加按钮的红色区域位置参考如下:
    UIContextMenu预览视图示意图

内容的提问来源于stack exchange,提问作者abhimuralidharan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 18:12:02