How to do `.datePickerStyle(isGraphical ? GraphicalDatePickerStyle() : WheelDatePickerStyle())`?

// this doesn't compile :(
// somehow make a `AnyDatePickerStyle`?
DatePicker("Pick a date", selection: $date)
    .labelsHidden()
    // error: Result values in '? :' expression have mismatching types 'GraphicalDatePickerStyle' and 'WheelDatePickerStyle'
    .datePickerStyle(isGraphical ? GraphicalDatePickerStyle() : WheelDatePickerStyle())

so have to do this:

// this works but prefer not to "swaps views out"
if isGraphical {
    DatePicker("Pick a date", selection: $date)
        .labelsHidden()
        .datePickerStyle(GraphicalDatePickerStyle())
} else {
    DatePicker("Pick a date", selection: $date)
        .labelsHidden()
        .datePickerStyle(WheelDatePickerStyle())
}

but would rather not swaps views out like this and the code doesn't look right: it's not obvious why it's this way.

Initially SwiftUI control styles like DatePickerStyle are enum's, so you can just pass in a different enum value to .datePickerStyle(:). But later they changed all the styles to be protocol values. So it's not possible to dynamically change style by passing different value to .xxxStyle(:) modifiers. Wonder what's the reason for this change?

Edit:

Initially SwiftUI control styles like DatePickerStyle are enum's

I mis-remember, it's was StaticMember, see: [Proposal] Static member lookup on protocol metatypes

The Style protocols work by passing you an underlying view and you wrapping it into another view context.

If there was an API to dynamically switch between two styles, it would still need to remove the old hierarchy that came from the decoration of the first style, and insert a new hierarchy from the decoration of the second style.

I think the if/else approach is the only thing that works here.

2 Likes

Ok, thanks! I'll pretty it up:

DatePicker("Pick a date", selection: $date)
    .labelsHidden()
    .if(isGraphical) { $0.datePickerStyle(GraphicalDatePickerStyle()) } else: { $0.datePickerStyle(WheelDatePickerStyle()) }