How to remove icon from Picker label?

I want to achieve these menus with a picker. The selected option only shows the text “Heart Rate” for example. And “<140 BPM” without the sf symbol.

And currently I have 2 problems. When using a “Label” or an “HStack” the menu shows an sf symbol before the text, like shown in this image down below.
And the 2nd problem is that the symbols are not taking the accent color, not even with .tint() or .foregroundStyle() or .foregroundColor()

Here is the code I’m using

Picker(selection: $viewModel.heartRateAlert) {
    ForEach(HeartRateAlertOptions.allCases, id: .self) { type in
        Label(type.title, systemImage: type.icon)
           .accentColor(type.iconColor) // this is not working, it's still white.
    }
} label: {
    Text("Heart Rate") // this should only show the text but its showing everything instead
}

3

You can transform the Picker into a LabeledContent + Menu + Picker structure like I did here, which gives you a lot more control over how the selected option is displayed.

struct ContentView: View {
    @State private var selection: HeartRateAlertOptions = .below140
    
    var body: some View {
        Form {
            LabeledContent("Heart Rate") {
                Menu {
                    Picker(selection: $selection) {
                        ForEach(HeartRateAlertOptions.allCases, id: .self) { option in
                            Label {
                                Text(option.title)
                            } icon: {
                                Image(systemName: option.icon)
                                    .symbolRenderingMode(.palette)
                                    .font(.title)
                                    .foregroundStyle(option.iconColor)
                            }
                        }
                    } label: {}
                } label: {
                    HStack {
                        Spacer()
                        Text(selection.title)
                        Image(systemName: "chevron.up.chevron.down")
                            .imageScale(.small)
                    }
                    .tint(.secondary)
                }
            }
        }
    }
}

// HeartRateAlertOptions is the same as in Benzy Neez's answer
enum HeartRateAlertOptions: CaseIterable {
    case below140
    case range140_152
    case range153_165
    case range166_177
    case over177

    var title: String {
        switch self {
        case .below140: "<140 BPM"
        case .range140_152: "140-152 BPM"
        case .range153_165: "153-165 BPM"
        case .range166_177: "166-177 BPM"
        case .over177: "+178 BPM"
        }
    }

    var icon: String {
        switch self {
        case .below140: "1.circle"
        case .range140_152: "2.circle"
        case .range153_165: "3.circle"
        case .range166_177: "4.circle"
        case .over177: "5.circle"
        }
    }

    var iconColor: Color {
        switch self {
        case .below140: .blue
        case .range140_152: .cyan
        case .range153_165: .green
        case .range166_177: .orange
        case .over177: .pink
        }
    }
}

Note that I used the .palette rendering mode to allow the symbol to be coloured using foregroundStyle.

Image(systemName: option.icon)
    .symbolRenderingMode(.palette)
    .font(.title)
    .foregroundStyle(option.iconColor)

I feel this is a much “cleaner” way to color an image, but compared to Benzy Neez’s answer, this seems to make the symbol’s font weight lighter.

Output:

Here are some ways to work around the limitations of the default Picker styling:

Colored icons

If you try to apply a tint or foreground style to a Label used as a menu item, the color gets ignored.

So, instead of creating the Label using the name of a system symbol, you can supply a colored Icon. This can be created using an Image.

I found that it doesn’t work to create a colored Image by supplying a system name in the usual way. [EDIT: Actually it can be done, Sweeper’s answer shows how. But you don’t have any control over the size or weight of the icon when doing it that way.] So another way is to use the initializer that takes drawing instructions and draw the symbol using a GraphicsContext:

private func coloredSymbol(type: HeartRateAlertOptions) -> some View {
    let symbol = Image(systemName: type.icon)
    let size = CGSize(width: 20, height: 20)
    return Image(size: size) { ctx in
        let resolvedSymbol = ctx.resolve(symbol)
        ctx.draw(
            resolvedSymbol,
            in: CGRect(origin: .zero, size: size)
        )
    }
    .foregroundStyle(type.iconColor)
}

Removing the icon from the label for the current selection

As you have probably discovered, it does not seem to be possible to use different label styles for the menu items and for the current selection. If you try to set a .labelStyle, it gets used for the menu items and the current selection.

As a workaround, you can use an overlay to mask the label for the current selection.

  • You can style the overlay any way you like, but you will probably want to mimic the styling of the default label, including the icon chevron.up.chevron.down.

  • To work effectively as a mask, the background needs to match the default background of a form field. I wasn’t able to identify a standard system background color that matches in both light and dark modes. However, you can switch colors depending on whether light or dark mode is in operation, if necessary.

  • Apply .allowsHitTesting(false) to the overlay, so that taps propagate through to the real label underneath.

EDIT: Sweeper’s answer shows a better way to replace the label, I’ll concede on that part!

Putting it all together

For testing, I created the following improvised version of the enum HeartRateAlertOptions. BTW, your screenshots suggest that you may have an issue with the titles of your enum values, two of the values seem to have the same title. Also, you may want to re-think the labelling for the first and last items (is it really <140, or <141?).

enum HeartRateAlertOptions: CaseIterable {
    case below140
    case range140_152
    case range153_165
    case range166_177
    case over177

    var title: String {
        switch self {
        case .below140: "<140 BPM"
        case .range140_152: "140-152 BPM"
        case .range153_165: "153-165 BPM"
        case .range166_177: "166-177 BPM"
        case .over177: "+178 BPM"
        }
    }

    var icon: String {
        switch self {
        case .below140: "1.circle"
        case .range140_152: "2.circle"
        case .range153_165: "3.circle"
        case .range166_177: "4.circle"
        case .over177: "5.circle"
        }
    }

    var iconColor: Color {
        switch self {
        case .below140: .blue
        case .range140_152: .cyan
        case .range153_165: .green
        case .range166_177: .orange
        case .over177: .pink
        }
    }
}

Here is the updated example, which runs standalone:

@State private var heartRateAlert: HeartRateAlertOptions = .below140
@Environment(.colorScheme) private var colorScheme: ColorScheme
var body: some View {
    Form {
        Picker("Heart Rate", selection: $heartRateAlert) {
            ForEach(HeartRateAlertOptions.allCases, id: .self) { type in
                Label {
                    Text(type.title)
                } icon: {
                    coloredSymbol(type: type)
                }
            }
        }
        .overlay(alignment: .trailing) {
            HStack(spacing: 5) {
                Text(heartRateAlert.title)
                Image(systemName: "chevron.up.chevron.down")
                    .dynamicTypeSize(.xSmall)
            }
            .font(.callout)
            .padding(.vertical, 8)
            .padding(.leading, 30)
            .foregroundStyle(Color(.secondaryLabel))
            .background(Color(colorScheme == .dark ? .systemGray6 : .systemBackground))
            .allowsHitTesting(false)
        }
    }
    .padding(.top, 400)
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật