Home > Mobile >  How to animate the transition between light and dark mode using SwiftUI?
How to animate the transition between light and dark mode using SwiftUI?

Time:05-16

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

CodePudding user response:

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

CodePudding user response:

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.

  • Related