2

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 get the colorScheme from the environment but I think I'm missing something.

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(RetroTheme.shared.appMainTint)) .frame(width: 50, height: 50, alignment: .center) if(self.colorScheme == .light) { .shadow(color: .secondary, radius: 5, x: 0, y: 0) } Image(systemName: "plus") .foregroundColor(Color.white) } } // End Button } } } } 
2
  • As dfd pointed out below the issue was trying to use an if statement with a modifier. See the updated code in the question. Commented Sep 15, 2019 at 13:51
  • Two things, I never saw your comment because you left the "at" (@) sign on your comment. Two years in and I'm still learning too! See my comment on my answer for what I hope you'll do. Between you and both answers this is something all can use. Commented Sep 15, 2019 at 14:38

4 Answers 4

7

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) } } } } 
Sign up to request clarification or add additional context in comments.

3 Comments

Much, much more elegant! It took me... a few hours... to get things working in my app that I proposed as a solution. (SwiftUI is new to us all.) As always, at least to me, you are a level or more above most of us UIKit coders (and I barely consider myself one of them). nSweet!
Thanks @dfd, so kind as always. I have compiled several view extensions aimed at making the code more readable. It's in my blog, as "View Extensions for Better Code Readability". Cheers ;-)
I check your blog regularly and already have been using one for corner radius. Didn't see this one - but it has me drilling into some by your use.
4

SwiftUI

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.


UIKit

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

Comments

2

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.

4 Comments

This didn't work for me. I get a error Function declares an opaque return type, but the return statements in its body do not have matching underlying types. Thanks for the info about using if statements on modifiers. With that I was able to get it working.
First, glad I helped. Second, good answer! Too bad it's an edit to your question? Please, post your answer as that! There's nothing wrong with that and I'd gladly upvote it. (You can't accept it - I think - but this site is really about both the Q and the A. And if I may? Edit the question title to reflect the real issue. This helps everyone!)
Will do, thanks. I'm still kind of new to Stack Overflow so I don't know all of the etiquette
@radicalappdev did you resolve that error? I'm getting the same, thanks
2

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) } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.