I am using SwiftUI and would like to set the pickerStyle of a View depending on the number of items in the Picker. With a few items, SegmentedPickerStyle() is ideal, with more WheelPickerStyle() is better.
}.pickerStyle(productsObserver.product.productFamilies?.count ?? 0 < 5 ? SegmentedPickerStyle() : WheelPickerStyle())
The function signature reads:
func pickerStyle<S>(_ style: S) -> some View where S : PickerStyle
which i have learned uses a generic in the functiona signature because PickerStyle uses an associated type.
It shouldn't be so difficult a problem and probably isn't - Protocols should work like this easy = , but i can't see it. Any help is highly appreciated!
pickerStyle
is a generic method that accepts a concrete type (at compile-time) that conforms PickerStyle
. So, it cannot be either SegmentedPickerStyle
or WheelPickerStyle
(determined at run-time) - it has to be one or the other.
So, one suggestion would be to create a view modifier and apply the picker style conditionally. The critical difference here is that it returns a conditional view of type _ConditionalContent<TrueContent, FalseContent>
.
struct PickerStyleOption<P1: PickerStyle, P2: PickerStyle>: ViewModifier {
let predicate: () -> Bool
let style1: P1
let style2: P2
@ViewBuilder
func body(content: Content) -> some View {
if predicate() {
content
.pickerStyle(style1)
} else {
content
.pickerStyle(style2)
}
}
}
For convenience, you could create an extension:
extension View {
func pickerStyleOption<P1: PickerStyle, P2: PickerStyle>(
_ condition: @autoclosure @escaping () -> Bool,
then style1: P1,
else style2: P2) -> some View {
self.modifier(
PickerStyleOption(predicate: condition, style1: style1, style2: style2)
)
}
}
And use it like so:
Picker(...) {
...
}
.pickerStyleOption((productsObserver.product.productFamilies?.count ?? 0) < 5,
then: SegmentedPickerStyle(), else: WheelPickerStyle())