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

如何为SwiftUI Picker自定义文本的字体与颜色?

解决SwiftUI Picker(MenuPickerStyle)自定义字体/颜色不生效的问题

问题原因

使用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)
        }
    }
}

额外注意事项

  1. 确保自定义字体名称正确,且已添加到项目中:
    • 将字体文件拖入Xcode,勾选"Add to targets"
    • 在Info.plist中添加Fonts provided by application字段,填入字体文件名(如SampleFont-Regular.ttf)
  2. 原代码中font(.custom("samble", size: 16))存在拼写错误,需修正为实际字体名称

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:27:23