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

macOS菜单栏:如何为当前选中的子菜单项添加勾选标记

解决macOS SwiftUI菜单单选勾选对齐问题

问题描述

我在开发macOS应用时,需要实现带有单选勾选标记的子菜单,要求和原生macOS应用(比如Vivaldi的「编辑>拼写和语法」菜单)一致:选中项左侧显示勾选标记,所有菜单项水平对齐,未选中项左侧留对应空格,且同一时间只能选一个选项。

试过多种方案都失败了:

  • HStack结合Image和Text,通过条件透明度控制显示:SwiftUI直接忽略了菜单项样式
  • HStack里放选中时显示的Image、Spacer和Text(勾选前置):菜单项无法对齐
  • HStack里放选中时显示的Image、Spacer和Text(勾选后置):菜单项还是不对齐
  • 使用Label组合文本和图标:完全无效

查了Apple的Menu文档也没找到子菜单标识符相关内容。更新:之前的简化方案适配我的完整代码时出错,完整主App代码如下:

import SwiftUI

@main
struct SimpleTrackerApp: App {
    @State var viewModel = ViewModel()
        
    func resetTracker() {
        viewModel.resetBosses()
        viewModel.resetItems()
    }

    struct settingsMenu: View {
        @Environment(ViewModel.self) private var viewModel
        
        var body: some View {
            ForEach(Array(viewModel.seedOptions.enumerated()), id: \.key) { index in
                Picker(viewModel.seedOptions[index].title, selection: $viewModel.seedOptions[index].selection) {
                    ForEach(Array(viewModel.seedOptions[index].options.enumerated()), id: \.offset) { offset, option in
                        Button(option) {}
                            .tag(offset)
                    }
                }
            }
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(viewModel)
        }
        .defaultSize(width: 857, height: 468)
        .commands {
            CommandGroup(replacing: .newItem) {
                Button("Reset Tracker") {
                    resetTracker()
                }
                .keyboardShortcut("R", modifiers: [.command])
            }
            CommandMenu("Settings") {
                settingsMenu()
                    .environment(viewModel)
            }
        }
    }
}

解决方案

针对你的代码结构,核心问题是用Button作为Picker选项无法触发原生菜单的单选勾选样式,直接利用SwiftUI Picker的原生行为即可实现需求,修改后的代码如下:

import SwiftUI

@main
struct SimpleTrackerApp: App {
    @State var viewModel = ViewModel()
        
    func resetTracker() {
        viewModel.resetBosses()
        viewModel.resetItems()
    }

    struct SettingsMenu: View {
        @Environment(ViewModel.self) private var viewModel
        
        var body: some View {
            ForEach(Array(viewModel.seedOptions.enumerated()), id: \.key) { index in
                Picker(selection: $viewModel.seedOptions[index].selection, label: Text(viewModel.seedOptions[index].title)) {
                    ForEach(Array(viewModel.seedOptions[index].options.enumerated()), id: \.offset) { offset, option in
                        Text(option)
                            .tag(offset)
                    }
                }
                .menuStyle(.borderlessButton) // 确保Picker在CommandMenu中作为子菜单正确展示
            }
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environment(viewModel)
        }
        .defaultSize(width: 857, height: 468)
        .commands {
            CommandGroup(replacing: .newItem) {
                Button("Reset Tracker") {
                    resetTracker()
                }
                .keyboardShortcut("R", modifiers: [.command])
            }
            CommandMenu("Settings") {
                SettingsMenu()
                    .environment(viewModel)
            }
        }
    }
}

// 补充ViewModel示例结构(确保你的ViewModel符合此格式)
class ViewModel: ObservableObject {
    struct SeedOption {
        let title: String
        var selection: Int
        let options: [String]
    }
    
    @Published var seedOptions: [SeedOption] = [
        SeedOption(title: "种子类型", selection: 0, options: ["普通", "进阶", "专家"]),
        SeedOption(title: "生成模式", selection: 1, options: ["默认", "自定义", "随机"])
    ]
    
    func resetBosses() {}
    func resetItems() {}
}

关键修改点:

  1. 替换Picker选项的Button为Text:SwiftUI会自动为选中的Text选项添加原生的勾选标记,并且所有选项自动对齐,无需手动处理空格或图标
  2. 添加.menuStyle(.borderlessButton):确保Picker在CommandMenu中作为可展开的子菜单正确渲染,保持原生菜单的交互逻辑
  3. 规范命名:将settingsMenu改为SettingsMenu,符合Swift的大驼峰命名规范

这样修改后,你的Settings菜单会完全匹配原生macOS的单选勾选样式,选中项左侧显示勾选标记,所有菜单项自动水平对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:23:12