skip to Main Content

I don’t know if this is supported yet with SwiftUI, but I’m trying to animate the transition from Light/Dark mode app-wide when the button is a. I have a navigation bar on the bottom of the screen with a button that switches from a sun to moon icon when tapped.

The switch from light mode to dark mode and vice-versa does work, but is immediate and looks like someone just flipped the lights off. The animation use in the following code only changes the image of my button with animation.

Here is what I have:

NavigationBarView.swift

struct NavigationBarView: View {

@AppStorage("isDarkMode") private var isDarkMode = false
...

var body: some View {
    ZStack {
        ...
            Button(action: {
                withAnimation(.easeInOut) {
                    isDarkMode.toggle()
                }
            }, label: {
                if isDarkMode {
                    Image.sunButton
                        .resizable()
                        .imageScale(.large)
                        .frame(width: 24, height: 24)
                        .foregroundColor(Color.darkGray)
                } else {
                    Image.moonButton
                        .resizable()
                        .imageScale(.large)
                        .frame(width: 24, height: 24)
                        .foregroundColor(Color.darkGray)
                }
                
            })
            
        ...
        
        }
    }
    ...
}

}

LucidityApp.swift

@main
struct LucidityApp: App {

@Environment(.colorScheme) var colorScheme
@AppStorage("isDarkMode") private var isDarkMode = false

var body: some Scene {
    WindowGroup {
        Dashboard()
            .preferredColorScheme(isDarkMode ? .dark : .light)
            .background(colorScheme == .dark ? Color.darkGray : Color.white)
    }
}

}

Thank you in advance for the help, and I am new to SwiftUI so if you have any best practice(s) tips, I will gladly listen to them!

Shane

EDIT: I found the solution, I wrapped the WindowGroup in the main app SwiftUI file in a VStack, and applied .animation to the VStack with .animation(.spring(), value: isDarkMode) and that made the transition from light to dark mode the way I wanted it.

2

Answers


  1. You’re doing the right thing to animate it in SwiftUI, so it must not work. Maybe file a bug with Apple?

    Luckily you can animate light/dark mode switch if you use UIKit instead. You’ll have to get ahold of your UIWindow(s) somehow and then animate the property overrideUserInterfaceStyle per this answer:

    if let window = UIApplication.shared.keyWindow {
        UIView.transition (with: window, duration: 0.3, options: .transitionCrossDissolve, animations: {
            window.overrideUserInterfaceStyle = .dark //.light or .unspecified
        }, completion: nil)
    }
    

    Just drop that code in your Button’s action and it should work.

    Login or Signup to reply.
  2. To get the animation to work you need to add a transition, Transitions control how the insertion and removal of a view takes place.

        Button(action: {
            withAnimation(.easeInOut) {
                isDarkMode.toggle()
            }
        }, label: {
            if isDarkMode {
                Image.sunButton
                    .resizable()
                    .imageScale(.large)
                    .frame(width: 24, height: 24)
                    .foregroundColor(Color.darkGray)
                    .transition(.asymmetric(insertion: .opacity, removal: .opacity))
            }
            else {
                Image.moonButton
                    .resizable()
                    .imageScale(.large)
                    .frame(width: 24, height: 24)
                    .foregroundColor(Color.darkGray)
                    .transition(.asymmetric(insertion: .opacity, removal: .opacity))
            }
            
        })
    

    How the transition behaves can also be changed depending on your needs please see apple documentation

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search