radicalappdev
radicalappdev

Reputation: 1422

SwiftUI - How do I check to see if dark mode is enabled?

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

}

Upvotes: 2

Views: 4280

Answers (4)

Mojtaba Hosseini
Mojtaba Hosseini

Reputation: 119302

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

Upvotes: 4

radicalappdev
radicalappdev

Reputation: 1422

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

Upvotes: 2

kontiki
kontiki

Reputation: 40519

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

Upvotes: 7

user7014451
user7014451

Reputation:

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.

Upvotes: 2

Related Questions