I am currently trying to implement a solution in an app where the user is supposed to be able to switch the app's appearance in real-time with the following options:
- System (applying whatever appearance is set in the iOS settings for the device)
- Light (applying .light color scheme)
- Dark (applying . dark color scheme)
Setting light and dark color schemes has proven to be quite easy and responsive using .preferredColorScheme(); however, I have not yet found any satisfying solution for the "System" option.
My current approach is the following:
- Getting the device color scheme using @Environment(.colorScheme) in ContentView
- Creating a custom view modifier for applying the respective color scheme on whatever view
- Using a modifier on "MainView" (that's where the real content of the app is supposed to live) to switch between the color schemes
My idea was to embed MainView in ContentView so that the @Environment(.colorScheme) would not be disturbed by any colorScheme that is applied to MainView.
However, it still doesn't work as supposed: When setting light and dark appearance, everything works as intended. However, when switching from light/dark to "system", the change in appearance is only visible after re-launching the app. Expected behavior, however, would be that the appearance changes instantly.
Any ideas on this?
Here are the relevant code snippets:
Main view
import SwiftUI
struct MainView: View {
@AppStorage("selectedAppearance") var selectedAppearance = 0
var body: some View {
VStack {
Spacer()
Button(action: {
selectedAppearance = 1
}) {
Text("Light")
}
Spacer()
Button(action: {
selectedAppearance = 2
}) {
Text("Dark")
}
Spacer()
Button(action: {
selectedAppearance = 0
}) {
Text("System")
}
Spacer()
}
}
}
ContentView
import SwiftUI
struct ContentView: View {
@Environment(\.colorScheme) var colorScheme
var body: some View {
MainView()
.modifier(ColorSchemeModifier(colorScheme: colorScheme))
}
}
"Utilities"
import Foundation
import SwiftUI
struct ColorSchemeModifier: ViewModifier {
@AppStorage("selectedAppearance") var selectedAppearance: Int = 0
var colorScheme: ColorScheme
func body(content: Content) -> some View {
if selectedAppearance == 2 {
return content.preferredColorScheme(.dark)
} else if selectedAppearance == 1 {
return content.preferredColorScheme(.light)
} else {
return content.preferredColorScheme(colorScheme)
}
}
}