惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

K
Kaspersky official blog
T
Threat Research - Cisco Blogs
N
News and Events Feed by Topic
Hacker News: Ask HN
Hacker News: Ask HN
Project Zero
Project Zero
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 叶小钗
Security Latest
Security Latest
Spread Privacy
Spread Privacy
aimingoo的专栏
aimingoo的专栏
N
News and Events Feed by Topic
Webroot Blog
Webroot Blog
U
Unit 42
Cyberwarzone
Cyberwarzone
小众软件
小众软件
Scott Helme
Scott Helme
Engineering at Meta
Engineering at Meta
Microsoft Security Blog
Microsoft Security Blog
T
The Blog of Author Tim Ferriss
A
About on SuperTechFans
爱范儿
爱范儿
S
Schneier on Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Schneier on Security
Schneier on Security
Latest news
Latest news
GbyAI
GbyAI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
The Register - Security
The Register - Security
WordPress大学
WordPress大学
博客园_首页
Blog — PlanetScale
Blog — PlanetScale
PCI Perspectives
PCI Perspectives
Jina AI
Jina AI
AI
AI
NISL@THU
NISL@THU
I
Intezer
G
GRAHAM CLULEY
B
Blog
S
Secure Thoughts
IT之家
IT之家
宝玉的分享
宝玉的分享
Recent Announcements
Recent Announcements
Y
Y Combinator Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
酷 壳 – CoolShell
酷 壳 – CoolShell
有赞技术团队
有赞技术团队
V2EX - 技术
V2EX - 技术
Recorded Future
Recorded Future
Hacker News - Newest:
Hacker News - Newest: "LLM"

看川博客

我被 AI "蒸馏" 了 - 看川博客 距离上线只差一个软件著作权证书 - 看川博客 开发简报(2):开发者需要先进的工具 - 看川博客 比越狱更棘手!iOS vPhone 虚拟机成黑灰产新温床 - 看川博客 开发简报(1):拥抱 AI、别无选择 - 看川博客 糟糕!我的 OpenClaw 中了病毒 - 看川博客 今天你用了多少词元? - 看川博客 闪忆 LiveMem:把回忆做成会动的壁纸 - 看川博客 Swift 从 ObservableObject 迁移到 @Observable 的再讨论 视频帧截图(Video2Frame)专业视频抽帧截图工具 - 看川博客 录音记事本 - 专业安全的录音工具 App - 看川博客 Swift 从 ObservableObject 迁移到 @Observable 从 Apple Distribution Managed 证书提取备案所需公钥和 SHA1 条码助手 iOS 2.0.0 升级指南 - 看川博客 C++ RTTI 信息对二进制体积和安全性的影响 - 看川博客 SwiftUI 系统颜色表查询 - 看川博客 读马伯庸《长安的荔枝》 - 看川博客 SwiftUI List selection 的使用提示 - 看川博客 PHP json_encode UTF-8 中文编码问题 - 看川博客 我为什么重新运营微信公众号 - 看川博客 使用 TrollStore(巨魔) 在非越狱设备上安装任意 IPA - 看川博客 条码助手小程序更新 - 看川博客 iOS 18 中 libdyld.dylib/dyld 的一些变化 涨粉神器?解密“抖音黑科技”云端商城 - 看川博客
SwiftUI Menu checkmark 文本对齐 - 看川博客
2025-05-06 · via 看川博客

SwiftUI 中实现 Menu 菜单在有 checkmark 等 icon 情形下的文本对齐,如果使用 Button 或其他自定义 View 很难到达想要的效果,可以使用 Picker 和 Toggle。

在很多原生 macOS App 中经常可以看到下面这种菜单选项选中状态和非选中状态文本对齐的布局:

SwiftUI Menu checkmark align

这种布局要求在未选中状态时不显示左侧的 icon,但是文本和选中状态保持左对齐。这个布局看样子很简单对不对?在 SwiftUI 中使用 Menu + Label 似乎很容易实现。

Menu("菜单") {
    Button {
    } label: {
        Label("kanchuan1", systemImage: "")
    }
    
    Button {
    } label: {
        Label("kanchuan2", systemImage: "")
    }
    
    // 选中
    Button {
    } label: {
        Label("kanchuan", systemImage: "checkmark")
    }
}.labelStyle(.titleAndIcon)

你可能很快会发现,Label 在 systemImage 传空时会忽略 icon。那么我们自定义 buttonStyle 或直接自定义布局呢,比如像下面这样:

struct MenuLabel: View {
    var imageName: String
    var text: String
    
    var body: some View {
        HStack(spacing: 4.0) {
            if imageName.isEmpty {
                EmptyView()
                    .frame(width: 20, height: 20)
            } else {
                Image(systemName: imageName)
                    .frame(width: 20, height: 20)
            }
            Text(text)
        }
    }
}

很遗憾,无论是使用 EmptyView、Spacer、Color.clear 构造空白视图,还是通过 hidden、opacity(0) 隐藏视图,一旦放入 Menu 组件中显示,都不能起作用。更离普的是,当我们试图通过使用 Unicode 文本字符的方式替代 checkmark Image 时,竟然会发生将空格字符忽略显示的情况。

Text(\(isSelected ? "✔️" : " ")\(kanchuan))

Menu 对其内部的视图施加了强有力的布局约束,会导致子视图本身的布局不再受控制。

正确的方式是什么?

不要尝试使用 Button,而是使用 Picker 和 Toggle,这两个组件会自带对齐效果,像下面这样。

var options: [String] = ["kanchuan1", "kanchuan2", "kanchuan3", "kanchuan4"]
@State var selectedOption = "kanchuan1"
...
Menu {
    Picker("菜单", selection: $selectedOption) {
        ForEach(options, id: \.self) { option in
            Text(option)
        }
    }
    
    Toggle(isOn: Binding<Bool>(
        get: {
            return true or false
        },
        set: { oldValue, newValue in
        	// set
        }))
    {
        Text("kanchuan5")
    }
    
    Toggle(isOn: Binding<Bool>(
        get: {
            return true or false
        },
        set: { oldValue, newValue in
        	// set
        }))
    {
        Text("kanchuan6")
    }
} label: {
    Text("Menu")
}

相关讨论:

How to align SwiftUI menu-item with checkmark in macOS?

在 SwiftUI 中,想要实现和 UIKit 那样的高度自定义布局有时候还是差一点意思,似乎 Apple 更倾向开发者使用官方推荐的方案解决问题。这到底是好还是不好呢?