5.7 C
New York
Sunday, March 9, 2025

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 type to a Label used as a menu merchandise, the colour will get ignored.

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

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

personal func coloredSymbol(kind: HeartRateAlertOptions) -> some View {
    let image = Picture(systemName: kind.icon)
    let dimension = CGSize(width: 20, top: 20)
    return Picture(dimension: dimension) { ctx in
        let resolvedSymbol = ctx.resolve(image)
        ctx.draw(
            resolvedSymbol,
            in: CGRect(origin: .zero, dimension: dimension)
        )
    }
    .foregroundStyle(kind.iconColor)
}

Eradicating the icon from the label for the present choice

As you’ve gotten most likely found, it doesn’t appear to be doable to make use of totally different label kinds for the menu objects and for the present choice. Should you attempt to set a .labelStyle, it will get used for the menu objects 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 type the overlay any method you want, however you’ll most likely wish 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 kind subject. I wasn’t in a position to establish a normal system background coloration that matches in each gentle and darkish modes. Nonetheless, you may swap colours relying on whether or not gentle or darkish mode is in operation, if obligatory.

  • 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 exchange 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’ll have a problem with the titles of your enum values, two of the values appear to have the identical title. Additionally, chances are you’ll wish to re-think the labelling for the primary and final objects (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 personal var heartRateAlert: HeartRateAlertOptions = .below140
@Surroundings(.colorScheme) personal var colorScheme: ColorScheme
var physique: some View {
    Kind {
        Picker("Coronary heart Fee", choice: $heartRateAlert) {
            ForEach(HeartRateAlertOptions.allCases, id: .self) { kind in
                Label {
                    Textual content(kind.title)
                } icon: {
                    coloredSymbol(kind: kind)
                }
            }
        }
        .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(.high, 400)
}

Screenshot

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles