swift – The best way to take away icon from Picker label?

swift – The best way to take away icon from Picker label?


Listed below are some methods to work across the limitations of the default Picker styling:

Coloured icons

Should you attempt to apply a tint or foreground model to a Label used as a menu merchandise, the colour will get ignored.

So, as an alternative of making the Label utilizing the title of a system image, you possibly can provide a coloured Icon. This may be created utilizing an Picture.

I discovered that it would not work to create a coloured Picture by supplying a system title within the common means. [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 one other means is to make use of the initializer that takes drawing directions and draw the image utilizing a GraphicsContext:

non-public func coloredSymbol(sort: HeartRateAlertOptions) -> some View {
    let image = Picture(systemName: sort.icon)
    let measurement = CGSize(width: 20, peak: 20)
    return Picture(measurement: measurement) { ctx in
        let resolvedSymbol = ctx.resolve(image)
        ctx.draw(
            resolvedSymbol,
            in: CGRect(origin: .zero, measurement: measurement)
        )
    }
    .foregroundStyle(sort.iconColor)
}

Eradicating the icon from the label for the present choice

As you may have in all probability found, it doesn’t appear to be attainable to make use of completely different label types for the menu gadgets and for the present choice. Should you attempt to set a .labelStyle, it will get used for the menu gadgets and the present choice.

As a workaround, you should use an overlay to masks the label for the present choice.

  • You’ll be able to model the overlay any means you want, however you’ll in all probability need to mimic the styling of the default label, together with the icon chevron.up.chevron.down.

  • To work successfully as a masks, the background must match the default background of a type discipline. I wasn’t capable of determine a typical system background colour that matches in each gentle and darkish modes. Nevertheless, you possibly can swap colours relying on whether or not gentle or darkish mode is in operation, if crucial.

  • Apply .allowsHitTesting(false) to the overlay, in order that faucets propagate by to the actual label beneath.

EDIT: Sweeper’s reply exhibits a greater strategy to change the label, I will concede on that half!

Placing all of it collectively

For testing, I created the next improvised model of the enum HeartRateAlertOptions. BTW, your screenshots recommend that you will have a difficulty with the titles of your enum values, two of the values appear to have the identical title. Additionally, chances are you’ll need to re-think the labelling for the primary and final gadgets (is it actually <140, or <141?).

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

    var title: String {
        swap 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 {
        swap 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: Coloration {
        swap self {
        case .below140: .blue
        case .range140_152: .cyan
        case .range153_165: .inexperienced
        case .range166_177: .orange
        case .over177: .pink
        }
    }
}

Right here is the up to date instance, which runs standalone:

@State non-public var heartRateAlert: HeartRateAlertOptions = .below140
@Surroundings(.colorScheme) non-public var colorScheme: ColorScheme
var physique: some View {
    Kind {
        Picker("Coronary heart Price", choice: $heartRateAlert) {
            ForEach(HeartRateAlertOptions.allCases, id: .self) { sort in
                Label {
                    Textual content(sort.title)
                } icon: {
                    coloredSymbol(sort: sort)
                }
            }
        }
        .overlay(alignment: .trailing) {
            HStack(spacing: 5) {
                Textual content(heartRateAlert.title)
                Picture(systemName: "chevron.up.chevron.down")
                    .dynamicTypeSize(.xSmall)
            }
            .font(.callout)
            .padding(.vertical, 8)
            .padding(.main, 30)
            .foregroundStyle(Coloration(.secondaryLabel))
            .background(Coloration(colorScheme == .darkish ? .systemGray6 : .systemBackground))
            .allowsHitTesting(false)
        }
    }
    .padding(.prime, 400)
}

Screenshot

Leave a Reply

Your email address will not be published. Required fields are marked *