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