I’m facing an issue and I’d like to know if anyone has already run into this.
I have a ContentView
that presents a SettingsView
as a sheet. SettingsView
applies a change to the app’s colorScheme. ContentView
reacts correctly to the change, and SettingsView does too (so far, so good).
What’s strange is that when I set nil on the preferredColorScheme
modifier (which, according to the docs, corresponds to the system color scheme), ContentView
correctly picks up the change and refreshes, while SettingsView
does pick up the change but doesn’t refresh. (In the video you can clearly see that when I switch from Dark to System, the parent view refreshes properly but not the presented sheet.)
I’ve tried everything—switching to UIKit, changing the sheet’s ID… nothing works
Another strange thing: if I present SettingsView
through a NavigationLink, everything works normally…
Here is a sample code to reproduce:
import SwiftUI
enum AppTheme: Int {
case system = 0
case dark = 1
case light = 2
var colorScheme: ColorScheme? {
switch self {
case .system: return nil
case .light: return .light
case .dark: return .dark
}
}
}
struct SettingsView: View {
@AppStorage("theme") var appTheme: AppTheme = .system
var body: some View {
VStack(spacing: 8) {
Button {
select(theme: .system)
} label: {
Text("Systeme")
}
Button {
select(theme: .dark)
} label: {
Text("Dark")
}
Button {
select(theme: .light)
} label: {
Text("Light")
}
}
.preferredColorScheme(appTheme.colorScheme)
}
func select(theme: AppTheme) {
appTheme = theme
}
}
struct ContentView: View {
@AppStorage("theme") var appTheme: AppTheme = .system
@State var isPresented = false
var body: some View {
NavigationStack {
VStack {
Button {
isPresented = true
} label: {
Text("Present settings")
}
// NavigationLink("Present settings") {
// SettingsView()
// }
}
.preferredColorScheme(appTheme.colorScheme)
.sheet(isPresented: $isPresented) {
SettingsView()
}
}
}
}
#Preview {
ContentView()
}
Someone (Andy) showed me a "workaround" (i guess?) by using the @Environment(\.colorScheme)
to update the proper color scheme for sheets (see the updated ContentView
)
BTW I still think this is a SwiftUI issue. Sheets should behave the same way other views are presented.
Here is a working version of the sample:
import SwiftUI
enum AppTheme: Int {
case system = 0
case dark = 1
case light = 2
var colorScheme: ColorScheme? {
switch self {
case .system: return nil
case .light: return .light
case .dark: return .dark
}
}
}
struct SettingsView: View {
@AppStorage("theme") var appTheme: AppTheme = .system
var body: some View {
VStack(spacing: 8) {
Button {
select(theme: .system)
} label: {
Text("System")
}
Button {
select(theme: .dark)
} label: {
Text("Dark")
}
Button {
select(theme: .light)
} label: {
Text("Light")
}
}
}
func select(theme: AppTheme) {
appTheme = theme
}
}
struct ContentView: View {
@AppStorage("theme") var appTheme: AppTheme = .system
@State var isPresented = false
@Environment(\.colorScheme) var systemColorScheme
private var effectiveColorScheme: ColorScheme {
// For sheets, we can't pass nil to preferredColorScheme, so we resolve the actual system scheme
appTheme.colorScheme ?? systemColorScheme
}
var body: some View {
NavigationStack {
VStack {
Button {
isPresented = true
} label: {
Text("Present settings")
}
}
.preferredColorScheme(appTheme.colorScheme)
.sheet(isPresented: $isPresented) {
SettingsView()
.preferredColorScheme(effectiveColorScheme)
}
}
}
}
#Preview {
ContentView()
}