简体   繁体   中英

Swift: Inline evaluation of multiple conditions for SwiftUI View

In SwiftUI, to modify a View based on a condition, we can use a ternary operator, hence allowing two cases. But what do I do if I want to evaluate multiple conditions, so that it's more like a switch (multiple cases) than an if / else (two cases)?

To demonstrate, a Text view can be modified by a @State var isLoggedIn: Bool like this, using a ternary operator:

Text(self.isLoggedIn ? "Welcome!" : "Please log in")

If I now want to add more cases, what I would do is use a function, but that makes the code a lot longer than the simple elegance of the ternary operator:

struct ContentView: View {

    enum Status {
        case loggedIn, loggedOut, expired
    }

    @State var userStatus: Status

    func displayMessage(status: Status) -> some View {
        switch(status) {
        case .loggedIn:
            return Text("Welcome!")
        case .loggedOut:
            return Text("Please log in")
        case .expired:
            return Text("Session expired")
        }
    }

    var body: some View {
        displayMessage(status: userStatus)
        // more views
    }
}

So does anyone have any suggestions on how I can simplify and shorten the second code?

Here is possible approach

struct ContentView: View {

    enum Status: String {
        case loggedIn  = "Welcome!"
        case loggedOut = "Please log in"
        case expired   = "Session expired"
    }

    @State var userStatus: Status = .loggedOut

    var body: some View {
        Text(userStatus.rawValue)

        // more views
    }
}

Your current solution is the most common code when it comes to use switch for an enum value for implementing SwiftUI views. I'd stick with this version even if it is a bit lengthy.

Having said that, to shorten it, you could use the switch inline without the separate func if you wrap it in a Group:

struct SwiftUISwitchView: View {

    @State var userStatus: Status = .loggedIn

    var body: some View {
        VStack {
            Group { () -> Text in
                switch(self.userStatus) {
                case .loggedIn:
                    return Text("Welcome!")
                case .loggedOut:
                    return Text("Please log in")
                case .expired:
                    return Text("Session expired")
                }
            }
        }
    }
}

Here is a handy overview question summarizing the options to use switch in SwiftUI views: Using switch/enums in SwiftUI Views

You don't need to return a Text , you could just return the String instead:

func displayMessage(status: Status) -> String {
    switch(status) {
    case .loggedIn:
        return "Welcome!"
    case .loggedOut:
        return "Please log in"
    case .expired:
        return "Session expired"
    }
}

var body: some View {
    Text(displayMessage(status: userStatus))
    // more views
}

This shortens your code by a little. To shorten it further, you could use a dictionary:

func displayMessage(status: Status) -> String {
    [Status.loggedIn: "Welcome",
     .loggedOut: "Please log in",
     .expired: "Session expired"][status]!
}

EDIT:

If you need userStatus to determine the appearance for another view, you can write another method that returns a corresponding value.


If you like the ternary operator so much , it can indeed be chained:

Text(
    userStatus == .loggedIn ? 
        "Welcome" : (userStatus == .loggedOut ? "Please log in" : "Session expired")
)

I wouldn't recommend this. It's not very readable. But this is indeed more "inline".

What you describe is possible in SwiftUI with just the ternary operator - see the description here: https://www.programiz.com/swift-programming/ternary-conditional-operator

It ends up being something like:

Text(self.isLoggedIn ? "Welcome!" : self.isNotLoggedIn ? "not welcome" : "who are you" )

where you can add as many extra conditions in between each: and? as you see fit. So, the example above corresponds to (with pseudocode):

if self.isLoggedIn {
  "Welcome"
}
else if self.isNotLoggedIn {
  "not welcome"
}
else {
"who are you"
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM