I have an app where I let the user choose the colorScheme, so that it can be left in adaptive mode or it can be forced to day or night mode, even if the system scheme of the device is different.
The issue is that the popover presented by the ColorPicker does not reflect the chosen ColorScheme, but only the system one (of the device).
The proposed code produces a list, which reflects automatically the preferredColorScheme, as an example. Then it produces a ColorPicker to set the background color and some tappable text to change the colorScheme to setColorScheme.
import SwiftUI
struct ColorPickerTest: View {
@Environment(\.colorScheme) var colorScheme
@State var setColorScheme: ColorScheme? = nil
@State var selectedColor = Color.green
var body: some View {
ZStack {
selectedColor.ignoresSafeArea()
VStack {
List {
ForEach(1..<6) { n in
Text("item \(n)")
}
}
.frame(height: 500)
.cornerRadius(30)
ColorPicker("Color", selection: $selectedColor)
.fixedSize().padding()
.background(colorScheme == .dark ? .blue : selectedColor)
.cornerRadius(30).padding()
HStack {
Text("Theme:")
Text("Adaptive").onTapGesture { setColorScheme = nil }
Text("Night").onTapGesture { setColorScheme = .dark }
Text("Day").onTapGesture { setColorScheme = .light }
}
}
}
.preferredColorScheme(setColorScheme)
}
}
#Preview {
ColorPickerTest()
}
This works well, except for the popover presented by ColorPicker, in that case the setColorScheme has no effect and only reflects the system scheme, ignoring the imposed preferredColorScheme.
Does anyone have a solution or an explanation?
macOS solution:
I don't know how to have SwiftUI's
ColorPickerautomatically apply background color, but I can propose this little hack:ColorPicker's window is aNSColorPanelthat we can search in the app's window hierarchy. There we can set its properties.Note that in
onAppearwe need to "wait" withDispatchQueue.main.asyncfor the panel to exist in the app'swindowsarray.You will still have to see how to apply your adaptive color scheme, but that how to apply the color if needed.
You can see from the print output, that the panel's initial
backgroundColoris "Catalog color: System windowBackgroundColor". So if you want to revert to have it repect the system's scheme, you'd have to set back to this value.