SwiftUI中如何为菜单添加副标题并实现选中项灰色显示?
实现苹果Stocks风格的选中项灰色菜单效果
SwiftUI原生的Picker(.menu)确实没有提供菜单展开时选中项灰色显示的默认样式,要实现这个效果,我们可以借助UIKit的UIMenu封装自定义组件,UIKit菜单支持更灵活的选中状态样式定制。
自定义菜单组件实现
import SwiftUI struct CustomMenuPicker: UIViewRepresentable { let systemImage: String let options: [(title: String, tag: Int)] @Binding var selectedTag: Int func makeUIView(context: Context) -> UIButton { let button = UIButton(type: .system) // 设置初始显示的标题和图标 if let selectedOption = options.first(where: { $0.tag == selectedTag }) { button.setTitle(selectedOption.title, for: .normal) } button.setImage(UIImage(systemName: systemImage), for: .normal) button.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 8) button.semanticContentAttribute = .forceRightToLeft // 让图标在文字左侧,匹配SwiftUI默认样式 // 构建菜单选项 let actions = options.map { option in let action = UIAction(title: option.title, state: option.tag == selectedTag ? .on : .off) { _ in selectedTag = option.tag button.setTitle(option.title, for: .normal) } // 给选中项设置灰色文字 if option.tag == selectedTag { let attributedTitle = NSAttributedString(string: option.title, attributes: [ .foregroundColor: UIColor.systemGray ]) action.attributedTitle = attributedTitle } return action } let menu = UIMenu(title: "", children: actions) button.menu = menu button.showsMenuAsPrimaryAction = true return button } func updateUIView(_ uiView: UIButton, context: Context) { // 选中状态变化时更新菜单样式 guard let menu = uiView.menu else { return } let updatedActions = options.map { option in let action = UIAction(title: option.title, state: option.tag == selectedTag ? .on : .off) { _ in selectedTag = option.tag uiView.setTitle(option.title, for: .normal) } if option.tag == selectedTag { let attributedTitle = NSAttributedString(string: option.title, attributes: [ .foregroundColor: UIColor.systemGray ]) action.attributedTitle = attributedTitle } else { action.attributedTitle = NSAttributedString(string: option.title) } return action } uiView.menu = UIMenu(title: "", children: updatedActions) // 更新按钮当前显示的标题 if let selectedOption = options.first(where: { $0.tag == selectedTag }) { uiView.setTitle(selectedOption.title, for: .normal) } } }
在SwiftUI视图中使用
struct ContentView: View { @State private var selectedOption = 0 var body: some View { CustomMenuPicker( systemImage: "chart.line.uptrend.xyaxis", options: [ (title: "Prijswijziging", tag: 0), (title: "Procentuele wijziging", tag: 1), (title: "Marktkapitalisatie", tag: 2) ], selectedTag: $selectedOption ) .padding() } }
关键说明
- 通过
UIButton结合UIMenu替代原生Picker,实现完全自定义的菜单样式 - 利用
UIAction的state标记选中状态,同时通过attributedTitle给选中项设置灰色文字,匹配Stocks应用的效果 updateUIView方法会在绑定的选中值变化时同步更新菜单的选中状态和文字样式
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

