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