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

如何从UIBarButtonItem有条件地显示UIMenu或弹窗?

解决方案(iOS 15.0+)

要实现点击UIBarButtonItem时先做运行时检查,满足条件才展示UIMenu,否则显示弹窗,你可以通过以下两种可靠方式实现:

方式一:利用底层UIButton触发菜单显示

直接获取UIBarButtonItem对应的底层UIButton实例,调用其showMenu方法手动展示菜单,这是最简洁的实现方式:

// 初始化按钮时绑定action
btnAdd = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addAction))

...

@objc func addAction(_ sender: UIBarButtonItem) {
    if someRuntimeCondition {
        // 动态创建UIMenu
        let menu = UIMenu(children: [
            UIAction(title: "新建文档", handler: { _ in
                // 处理新建文档逻辑
            }),
            UIAction(title: "新建文件夹", handler: { _ in
                // 处理新建文件夹逻辑
            })
        ])
        
        // 给按钮绑定菜单
        sender.menu = menu
        
        // 获取底层UIButton并触发菜单显示
        if let button = sender.value(forKey: "view") as? UIButton {
            button.showMenu(from: button, rect: button.bounds, preferredEdge: .bottom)
        }
    } else {
        // 显示条件不满足的弹窗
        let alert = UIAlertController(title: "提示", message: "当前无法执行此操作", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        present(alert, animated: true)
    }
}

说明:value(forKey: "view")用于获取UIBarButtonItem对应的原生UIButton,在iOS 15及以上版本中该属性稳定可用,不会出现兼容性问题。

方式二:使用UIContextMenuInteraction展示菜单

如果不想依赖底层控件的私有属性,可以通过UIContextMenuInteraction手动触发菜单展示,这种方式更符合官方API设计规范:

1. 实现UIContextMenuInteractionDelegate

在你的ViewController中扩展实现代理方法,用于提供菜单内容:

extension YourViewController: UIContextMenuInteractionDelegate {
    func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
        return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
            // 返回需要展示的UIMenu
            return UIMenu(children: [
                UIAction(title: "新建文档", handler: { _ in
                    // 处理逻辑
                }),
                UIAction(title: "新建文件夹", handler: { _ in
                    // 处理逻辑
                })
            ])
        }
    }
}

2. 在action中触发菜单展示

@objc func addAction(_ sender: UIBarButtonItem) {
    if someRuntimeCondition {
        guard let buttonView = sender.value(forKey: "view") as? UIView,
              let _ = buttonView.window else { return }
        
        // 创建上下文菜单交互对象
        let interaction = UIContextMenuInteraction(delegate: self)
        buttonView.addInteraction(interaction)
        
        // 触发菜单展示
        interaction.showMenu(at: buttonView.bounds, in: buttonView, preferredEdge: .bottom)
        
        // 菜单展示后移除交互,避免重复添加
        DispatchQueue.main.async {
            buttonView.removeInteraction(interaction)
        }
    } else {
        // 显示弹窗
        let alert = UIAlertController(title: "提示", message: "当前无法执行此操作", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        present(alert, animated: true)
    }
}

说明:这种方式不依赖UIBarButtonItem的menu属性,完全通过上下文交互来控制菜单展示,适合对API调用严谨性有要求的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:35:40