I'm trying to create a generic view modifier I can use for rapid prototyping.
struct If : ViewModifier {
var test: Bool
var then: (_: Content) -> Content
@ViewBuilder func body(content: Content) -> some View {
if test {
then(content)
} else {
content
}
}
}
What's the proper incantation to apply it to an element in the view?
struct ExampleView: View {
var isActive: Bool
HStack {}.modifier(If(test: isActive, then: ??? ))
}
My goal here is to be able to chain function calls conditionally on HStack and other items (e.g. .frame()
)
CodePudding user response:
It is difficult—probably impossible—to write this as a type conforming to ViewModifier
. You give this type for then
:
var then: (_: Content) -> Content
However, you're usually going to want then
to return a different type than it was given, because that's how modifiers generally work. For example, Text("hello")
has type Text
, but Text("hello").background(Color.red)
has type ModifiedContent<Text, _BackgroundStyleModifier<Color>>
.
We can try making the modifier generic over the type returned by then
:
struct If<Then: View>: ViewModifier {
var test: Bool
@ViewBuilder
var then: (_: Content) -> Then
@ViewBuilder
func body(content: Content) -> some View {
if test {
then(content)
} else {
content
}
}
}
But then we run into a problem when we try to use the modifier:
struct ExampleView: View {
var isActive: Bool
var body: some View {
HStack {
}.modifier(If(test: isActive, then: { $0.background(.red) }))
// ^