如何为SwiftUI Picker自定义文本的字体与颜色?
问题原因
使用MenuPickerStyle时,Picker的弹出菜单和选中项会采用UIKit原生菜单组件渲染,SwiftUI直接给Text设置的字体、颜色样式会被系统默认样式覆盖,导致自定义样式失效。
解决方案
方案一:用Menu组件替代Picker(推荐,完全自定义)
通过Menu组件重构Picker逻辑,可完全控制选中项和弹出选项的样式:
import Foundation import SwiftUI // Enums保持不变 enum EventFilter: String, CaseIterable, Identifiable { case all = "All" case liked = "Liked" case attending = "Attending" case pendingApproval = "Pending Approval" var id: String { self.rawValue } } enum EventSort: String, CaseIterable, Identifiable { case date = "Date" case title = "Title" var id: String { self.rawValue } } struct ColorUtils { static let darkPurple = Color(red: 51 / 255, green: 0 / 255, blue: 102 / 255) static let lightPurple = Color(red: 245 / 255, green: 240 / 255, blue: 255 / 255) } struct FilterSortView: View { @Binding var selectedFilter: EventFilter @Binding var selectedSort: EventSort var body: some View { HStack(spacing: 20) { // 筛选菜单 Menu { ForEach(EventFilter.allCases) { filter in Button(action: { selectedFilter = filter }) { HStack { Text(filter.rawValue) .font(.custom("sample", size: 16)) // 注意修正原代码中的"samble"拼写错误 .foregroundColor(ColorUtils.darkPurple) if selectedFilter == filter { Image(systemName: "checkmark") .foregroundColor(ColorUtils.darkPurple) } } } } } label: { HStack(spacing: 4) { Text(selectedFilter.rawValue) .font(.custom("sample", size: 16)) .foregroundColor(ColorUtils.darkPurple) Image(systemName: "chevron.down") .foregroundColor(ColorUtils.darkPurple) } } // 排序菜单 Menu { ForEach(EventSort.allCases) { sort in Button(action: { selectedSort = sort }) { HStack { Text(sort.rawValue) .font(.custom("sample", size: 16)) .foregroundColor(ColorUtils.darkPurple) if selectedSort == sort { Image(systemName: "checkmark") .foregroundColor(ColorUtils.darkPurple) } } } } } label: { HStack(spacing: 4) { Text(selectedSort.rawValue) .font(.custom("sample", size: 16)) .foregroundColor(ColorUtils.darkPurple) Image(systemName: "chevron.down") .foregroundColor(ColorUtils.darkPurple) } } } .padding() } } // Preview保持不变 struct FilterSortView_Previews: PreviewProvider { @State static var selectedFilter: EventFilter = .all @State static var selectedSort: EventSort = .date static var previews: some View { FilterSortView(selectedFilter: $selectedFilter, selectedSort: $selectedSort) .previewLayout(.sizeThatFits) } }
方案二:通过UIAppearance修改系统菜单样式(保留Picker结构)
如果想继续使用MenuPickerStyle,可通过UIKit的外观代理全局修改菜单样式,同时自定义Picker的选中项标签:
struct FilterSortView: View { @Binding var selectedFilter: EventFilter @Binding var selectedSort: EventSort var body: some View { HStack { // 自定义标签的Picker Picker(selection: $selectedFilter) { ForEach(EventFilter.allCases) { filter in Text(filter.rawValue).tag(filter) } } label: { HStack(spacing: 4) { Text(selectedFilter.rawValue) .font(.custom("sample", size: 16)) .foregroundColor(ColorUtils.darkPurple) Image(systemName: "chevron.down") .foregroundColor(ColorUtils.darkPurple) } } .pickerStyle(MenuPickerStyle()) Picker(selection: $selectedSort) { ForEach(EventSort.allCases) { sort in Text(sort.rawValue).tag(sort) } } label: { HStack(spacing: 4) { Text(selectedSort.rawValue) .font(.custom("sample", size: 16)) .foregroundColor(ColorUtils.darkPurple) Image(systemName: "chevron.down") .foregroundColor(ColorUtils.darkPurple) } } .pickerStyle(MenuPickerStyle()) } .padding() .onAppear { // 修改弹出菜单选项的样式 guard let customFont = UIFont(name: "sample", size: 16) else { return } UIMenuItem.appearance().setTitleTextAttributes([ .font: customFont, .foregroundColor: UIColor(ColorUtils.darkPurple) ], for: .normal) } .onDisappear { // 恢复系统默认样式(避免影响其他页面) UIMenuItem.appearance().setTitleTextAttributes(nil, for: .normal) } } }
额外注意事项
- 确保自定义字体名称正确,且已添加到项目中:
- 将字体文件拖入Xcode,勾选"Add to targets"
- 在
Info.plist中添加Fonts provided by application字段,填入字体文件名(如SampleFont-Regular.ttf)
- 原代码中
font(.custom("samble", size: 16))存在拼写错误,需修正为实际字体名称
内容的提问来源于stack exchange,提问作者Alkis Toutziaridis
相关产品推荐
相关产品推荐

