Andrew
Andrew

Reputation: 11337

How to apply modifier or view by condition

@State var modifierEnabled : Bool

struct BlankModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
    }
}

extension View {
    func TestModifierView() -> some View{
       return self.modifier(BlankModifier())
    }
}

How to apply TestModifierView only in case of modifierEnabled == true ?

Upvotes: 4

Views: 2536

Answers (2)

Andrew
Andrew

Reputation: 11337

@available(OSX 11.0, *)
public extension View {
    @ViewBuilder
    func `if`<Content: View>(_ condition: Bool, content: (Self) -> Content) -> some View {
        if condition {
            content(self)
        } else {
            self
        }
    }
}

@available(OSX 11.0, *)
public extension View {
    @ViewBuilder
    func `if`<TrueContent: View, FalseContent: View>(_ condition: Bool, ifTrue trueContent: (Self) -> TrueContent, else falseContent: (Self) -> FalseContent) -> some View {
        if condition {
            trueContent(self)
        } else {
            falseContent(self)
        }
    }
}

usage example ( one modifier ) :

Text("some Text")
   .if(modifierEnabled) { $0.foregroundColor(.Red) }

usage example2 (two modifier chains related to condition) :

Text("some Text")
   .if(modifierEnabled) { $0.foregroundColor(.red) } 
   else:                { $0.foregroundColor(.blue).background(Color.green) }

BUT!!!!!!!!!!!

Important thing that this modifier can be reason of some indentity issues. (later you will understand this)

So in some cases better to use standard if construction

Upvotes: 11

Paul B
Paul B

Reputation: 5125

I like the solution without type erasers. It looks strict and elegant.

public extension View {
    @ViewBuilder
    func modify<TrueContent: View, FalseContent: View>(_ condition: Bool, ifTrue modificationForTrue: (Self) -> TrueContent, ifFalse modificationForFalse: (Self) -> FalseContent) -> some View {
        if condition {
            modificationForTrue(self)
        } else {
            modificationForFalse(self)
        }
    }
}

Usage

HStack {
...
            }
            .modify(modifierEnabled) { v in
                    v.font(.title)
                } ifFalse: {
                    $0.background(Color.red) // even shorter
                }

If you only plan to apply a modifier (or a chain of modifiers) consider this:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
    @ViewBuilder func modifier<VM1: ViewModifier, VM2: ViewModifier>(_ condition: @autoclosure () -> Bool, applyIfTrue: VM1, applyIfFalse: VM2
) -> some View {
        if condition() {
           self.modifier(applyIfTrue)
        } else {
           self.modifier(applyIfFalse)
        }
    }
}

Usage is almost as simple as with regular .modifier.

...

    Form {
        HStack {
...
            }
            .modifier(modifierEnabled, applyIfTrue: CornerRotateModifier(amount: 8, anchor: .bottomLeading), applyIfFalse: EmptyModifier())

...

You can omit applyIfFalse part for conciseness and just return self.erase() if condition is false.

Upvotes: 0

Related Questions