Last active
November 29, 2024 15:53
-
-
Save ryanlintott/0bb21cd36a55f519bda5b441736edefe to your computer and use it in GitHub Desktop.
Custom color scheme view modifier for SwiftUI. Sets the color scheme to light mode, dark mode, or matches the system. If set to match, the app will respond to system-wide color scheme changes properly. A simple widget color scheme implementation is also provided.
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
import SwiftUI | |
enum CustomColorScheme: Int, CaseIterable, Identifiable, Codable { | |
static var defaultKey = "customColorScheme" | |
static var defaultValue = CustomColorScheme.system | |
case system = 0 | |
case light = 1 | |
case dark = 2 | |
var id: Int { | |
self.rawValue | |
} | |
var colorScheme: ColorScheme? { | |
switch self { | |
case .system: | |
return nil | |
case .light: | |
return .light | |
case .dark: | |
return .dark | |
} | |
} | |
var label: String { | |
switch self { | |
case .system: | |
return "System" | |
case .light: | |
return "Light" | |
case .dark: | |
return "Dark" | |
} | |
} | |
} |
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
import SwiftUI | |
struct CustomColorSchemeExampleView: View { | |
// Store custom color scheme in UserDefaults | |
@AppStorage(CustomColorScheme.defaultKey) var customColorScheme = CustomColorScheme.defaultValue | |
var body: some View { | |
Text("Hello World") | |
.customColorScheme($customColorScheme) | |
} | |
} |
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
import SwiftUI | |
struct CustomColorSchemeViewModifier: ViewModifier { | |
// This variable holds the currently active colour scheme (changed with calls to preferredColorScheme) | |
@Environment(\.colorScheme) var colorScheme | |
@Binding var customColorScheme: CustomColorScheme | |
// Temp value used for changing colorScheme when switching customColorScheme to .system | |
@State private var tempColorScheme: ColorScheme? = nil | |
init(_ customColorScheme: Binding<CustomColorScheme>) { | |
self._customColorScheme = customColorScheme | |
} | |
// This function is required to get the system color scheme | |
func getSystemColorScheme() -> ColorScheme { | |
return UITraitCollection.current.userInterfaceStyle == .light ? .light : .dark | |
} | |
func body(content: Content) -> some View { | |
content | |
.preferredColorScheme(tempColorScheme ?? customColorScheme.colorScheme) | |
.onChange(of: customColorScheme) { value in | |
if value == .system { | |
tempColorScheme = getSystemColorScheme() | |
} | |
} | |
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in | |
if customColorScheme == .system { | |
let systemColorScheme = getSystemColorScheme() | |
if systemColorScheme != colorScheme { | |
tempColorScheme = systemColorScheme | |
} | |
} | |
} | |
.onChange(of: tempColorScheme) { value in | |
if value != nil { | |
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { | |
// Resets tempColorScheme back to nil. This occurs after colorScheme has been updated | |
tempColorScheme = nil | |
} | |
} | |
} | |
} | |
} | |
extension View { | |
func customColorScheme(_ customColorScheme: Binding<CustomColorScheme>) -> some View { | |
self.modifier(CustomColorSchemeViewModifier(customColorScheme)) | |
} | |
} |
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
import SwiftUI | |
import WidgetKit | |
struct WidgetCustomColorSchemeExampleView: View { | |
// Use an app group to store and let users change it by referencing the same variable in your app. | |
@AppStorage(CustomColorScheme.defaultKey, store: "com.your.groupstore") var customColorScheme = CustomColorScheme.defaultValue | |
var body: some View { | |
Text("Hello World") | |
.widgetCustomColorScheme(customColorScheme) | |
} | |
} |
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
import SwiftUI | |
import WidgetKit | |
struct WidgetCustomColorSchemeViewModifier: ViewModifier { | |
// As we're not changing the preferred color scheme we can trust this to always be the system value | |
@Environment(\.colorScheme) var colorScheme | |
let customColorScheme: CustomColorScheme | |
init(_ customColorScheme: CustomColorScheme) { | |
self.customColorScheme = customColorScheme | |
} | |
func body(content: Content) -> some View { | |
content | |
// .preferredColorScheme doesn't work on widgets | |
.colorScheme(customColorScheme.colorScheme ?? colorScheme) | |
} | |
} | |
extension View { | |
func widgetCustomColorScheme(_ customColorScheme: CustomColorScheme) -> some View { | |
self.modifier(WidgetCustomColorSchemeViewModifier(customColorScheme)) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment