How do I check to see if dark mode on the device is enabled. I want to check this from within a view and conditionally show or hide a shadow.
I thought I could jus g
You are using colorScheme
correctly. But it looks like you have a different issue - placing a modifier inside an if
statement. I found that, unlike a View
, modifiers don't work that way.
The answer is to create a custom ViewModifier
. In your case I'd package everything up into one modifier like this:
struct CircleStyle: ViewModifier {
@Environment (\.colorScheme) var colorScheme:ColorScheme
func body(content: Content) -> some View {
if colorScheme == .light {
return content
.foregroundColor(Color(RetroTheme.shared.appMainTint))
.frame(width: 50, height: 50, alignment: .center)
.shadow(color: .secondary, radius: 5, x: 0, y: 0)
} else {
return content
.foregroundColor(Color(RetroTheme.shared.appMainTint))
.frame(width: 50, height: 50, alignment: .center)
}
}
And to use it:
Circle()..modifier(CircleStyle())
If you need to add more variables from your model, simply pass it into your modifier.
In my code, I have a simple View extension, that makes the code a lot more readable. With it, I can apply modifiers conditionally:
.conditionalModifier(self.colorScheme == .light, LightShadow())
The full implementation is below:
extension View {
// If condition is met, apply modifier, otherwise, leave the view untouched
public func conditionalModifier<T>(_ condition: Bool, _ modifier: T) -> some View where T: ViewModifier {
Group {
if condition {
self.modifier(modifier)
} else {
self
}
}
}
}
struct FloatingAddButton : View {
@Environment(\.colorScheme) var colorScheme
@Binding var openAddModal: Bool
var body : some View {
VStack {
Spacer()
HStack() {
Spacer()
Button(action: { self.openAddModal = true }) {
ZStack {
Circle()
.foregroundColor(Color(.red))
.frame(width: 50, height: 50, alignment: .center)
.conditionalModifier(self.colorScheme == .light, LightShadow())
Image(systemName: "plus")
.foregroundColor(Color.white)
}
}
} // End Button
}
}
}
struct LightShadow: ViewModifier {
func body(content: Content) -> some View {
content.shadow(color: .secondary, radius: 5, x: 0, y: 0)
}
}
If you ever have a case where you want to apply different modifiers for true and false, here's another extension:
extension View {
// Apply trueModifier if condition is met, or falseModifier if not.
public func conditionalModifier<M1, M2>(_ condition: Bool, _ trueModifier: M1, _ falseModifier: M2) -> some View where M1: ViewModifier, M2: ViewModifier {
Group {
if condition {
self.modifier(trueModifier)
} else {
self.modifier(falseModifier)
}
}
}
}
Thanks to @dfd for pointing out that I can't use an if statement with a modifier. I updated my code like this for now. This just returns different versions of the circle in light and dark mode.
if colorScheme == .light {
Circle()
.foregroundColor(Color(RetroTheme.shared.appMainTint))
.frame(width: 50, height: 50, alignment: .center)
.shadow(color: .secondary, radius: 5, x: 0, y: 0)
} else {
Circle()
.foregroundColor(Color(RetroTheme.shared.appMainTint))
.frame(width: 50, height: 50, alignment: .center)
}
With the \.colorScheme
key of an Environment
variable:
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
Text(colorScheme == .dark ? "In dark mode" : "In light mode")
}
}
Also, it automatically updates on the change of the environment color scheme.
To check the current, all object those conform to UITraitEnvironment
protocol, including all UIView
subclasses and all UIViewConttroller
subclasses have access to the current style:
myUIView.traitCollection.userInterfaceStyle == .dark
myUIViewController.traitCollection.userInterfaceStyle == .dark
To detect the change of the style, here is the full detailed answer