Reputation: 708
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?
Upvotes: 5
Views: 2318
Reputation: 2040
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"
}
Upvotes: 2
Reputation: 4082
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
Upvotes: 2
Reputation: 271810
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".
Upvotes: 1
Reputation: 257779
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
}
}
Upvotes: 2