Created
September 11, 2024 18:36
-
-
Save chockenberry/a2a23a12604e333b1c2a8b71e7a24155 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ColorSchemeApp.swift | |
// ColorScheme | |
// | |
// Created by Craig Hockenberry on 9/11/24. | |
// | |
import SwiftUI | |
@main | |
struct ColorSchemeApp: App { | |
@AppStorage("preferredColorScheme") private var preferredColorScheme: ColorScheme? | |
var body: some Scene { | |
WindowGroup { | |
ContentView() | |
.preferredColorScheme(preferredColorScheme) | |
} | |
.onChange(of: preferredColorScheme) { oldValue, newValue in | |
print("ColorSchemeApp: preferredColorScheme: \(oldValue) -> \(newValue)") | |
} | |
} | |
} | |
// NOTE: This allows @AppStorage to store an optional ColorScheme | |
extension ColorScheme: RawRepresentable { | |
public init?(rawValue: Int) { | |
guard let userInterfaceStyle = UIUserInterfaceStyle(rawValue: rawValue), | |
userInterfaceStyle != .unspecified, | |
let colorScheme = ColorScheme(userInterfaceStyle) | |
else { | |
//print("ColorScheme init: colorScheme = nil, rawValue = \(rawValue)") | |
return nil | |
} | |
//print("ColorScheme init: colorScheme = \(colorScheme), userInterfaceStyle = \(userInterfaceStyle)") | |
self = colorScheme | |
} | |
public var rawValue: Int { | |
let userInterfaceStyle = UIUserInterfaceStyle(self) | |
//print("ColorScheme rawValue: self = \(self), userInterfaceStyle = \(userInterfaceStyle)") | |
return userInterfaceStyle.rawValue | |
} | |
} | |
// NOTE: This provides a display name for an optional ColorScheme | |
extension ColorScheme? { | |
public var displayName: String { | |
if let self { | |
switch self { | |
case .dark: return "Dark" | |
case .light: return "Light" | |
@unknown default: | |
return "Unknown" | |
} | |
} | |
else { | |
return "System" | |
} | |
} | |
} | |
struct ContentView: View { | |
@State private var presentSettings = false | |
@State private var identityHack: Int = 0 | |
@AppStorage("preferredColorScheme") private var preferredColorScheme: ColorScheme? | |
var body: some View { | |
VStack(spacing: 40) { | |
Text(preferredColorScheme.displayName).font(.headline) | |
Button("Show Settings") { | |
presentSettings = true | |
} | |
} | |
.padding() | |
.sheet(isPresented: $presentSettings) { | |
SettingsView() | |
.id(identityHack) // an attempt to force an update by changing structural identity | |
.preferredColorScheme(preferredColorScheme) | |
.onChange(of: identityHack) { oldValue, newValue in | |
print("SettingView: identityHack: \(oldValue) -> \(newValue)") | |
} | |
} | |
.onChange(of: preferredColorScheme) { oldValue, newValue in | |
print("ContentView: preferredColorScheme: \(oldValue) -> \(newValue)") | |
identityHack += 1 | |
} | |
} | |
} | |
struct SettingsView: View { | |
@Environment(\.dismiss) private var dismiss | |
@State private var path = NavigationPath() | |
@AppStorage("preferredColorScheme") private var preferredColorScheme: ColorScheme? | |
var body: some View { | |
NavigationStack(path: $path) { | |
Form { | |
Section { | |
Picker("Theme", selection: $preferredColorScheme) { | |
Text("System").tag(nil as ColorScheme?) | |
Text("Dark").tag(ColorScheme.dark as ColorScheme?) | |
Text("Light").tag(ColorScheme.light as ColorScheme?) | |
} | |
} | |
} | |
.toolbar { | |
ToolbarItem(placement: .confirmationAction) { | |
Button("Done") { | |
dismiss() | |
} | |
} | |
} | |
} | |
} | |
} | |
#Preview { | |
ContentView() | |
} |
For reference, this method is not fully working and I can't really tell why.
I recorded a short video to showcase the issue (iOS 18 simulator, but same behavior in my device). As you'll see, I can toggle the system color scheme in the beginning and the app changes. However, when I change the setting to 'Dark' and then back to 'System', the app stays dark and no longer updates when the system color scheme changes.
ColorSchemeNotWorking.mp4
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
A full working solution is below: