Is there a Swifty way to detect the background color of a window in SwiftUI on macOS, that would work reliably regardless of the current theme (Dark Mode or Light Mode)?
For example, if one were to make a solid rectangle that "blends in" with the window's background, which color would they use?
This answer suggests the use of NSColor.xxxBackgroundColor
: SwiftUI: Get the Dynamic Background Color (Dark Mode or Light Mode)
However, this doesn't quite work for me. Here's some test code (Xcode 12.5, Swift 5.4) that makes three rectangles of various NSColor
s. I am looking for the one that blends in with the background.
struct TestView: View {
var body: some View {
VStack(spacing: 20) {
Text("This text is on the default background")
HStack(spacing: 30) {
Text("windowBackgroundColor")
.frame(width: 200, height: 100)
.background(Color(NSColor.windowBackgroundColor))
Text("underPageBackgroundColor")
.frame(width: 200, height: 100)
.background(Color(NSColor.underPageBackgroundColor))
Text("textBackgroundColor")
.frame(width: 200, height: 100)
.background(Color(NSColor.textBackgroundColor))
}
}
.padding(20)
}
}
In Dark mode, it seems NSColor.underPageBackgroundColor
matches the window's background.
The window's background is not composed by a color, is a NSVisualEffectView
with .windowBackground
as material
.
You can achieve that with this code:
struct EffectView: NSViewRepresentable {
@State var material: NSVisualEffectView.Material = .headerView
@State var blendingMode: NSVisualEffectView.BlendingMode = .withinWindow
func makeNSView(context: Context) -> NSVisualEffectView {
let view = NSVisualEffectView()
view.material = material
view.blendingMode = blendingMode
return view
}
func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
nsView.material = material
nsView.blendingMode = blendingMode
}
}
And apply that to your view:
struct ContentView: View {
var body: some View {
EffectView(material: .windowBackground)
.overlay(Text("Window Real Background"))
.padding(30)
}
}
The output is this (nothing to see because it mimetizes with background):
The reason why the background is an NSVisualEffectView is because the Window Tinting of macOS Big Sur, that changes the background according to wallpaper predominant color:
You can use @Environment
variables to get the ColorScheme that is being produced. In iOS I often use it like this, however it should translate to MacOS as well. There is no way to GET a view's color dynamically, because it is a set value that is not accessible. The best you can do is set the view, in a known state, and then pass that color around as needed. In my example I just used Color.black and Color.white
but you can easily assign any color to a variable and pass it around so that it is known.
@Environment(\.colorScheme) var colorScheme
struct TestView: View {
var body: some View {
VStack(spacing: 20) {
Text("This text is on the default background")
HStack(spacing: 30) {
Text("windowBackgroundColor")
.frame(width: 200, height: 100)
.background(colorScheme == .dark ? Color.black : Color.white)
Text("underPageBackgroundColor")
.frame(width: 200, height: 100)
.background(colorScheme == .dark ? Color.black : Color.white)
Text("textBackgroundColor")
.frame(width: 200, height: 100)
.background(colorScheme == .dark ? Color.black : Color.white)
}
}
.background(colorScheme == .dark ? Color.black : Color.white)
.padding(20)
}
}
In your case you can alternate the colors to the system colors that you're wanting to use. Setting based on the colorScheme
for the particular color you want on that view. Eg...
var windowBGColor = NSColor.windowBackgroundColor
var underPageBGColor = NSColor.underPageBackgroundColor
var textBGColor = NSColor.textBackgroundColor
var sampleColor = colorScheme == .dark ? windowBGColor : textBGColor
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.