12

在我的 Web 视图中,我使用 CSS 变量在运行时更改各种颜色,具体取决于是否启用了 macOS 10.14 的暗模式。这么多工作正常。棘手的部分是在系统外观发生变化时更新颜色。

我通过观察effectiveAppearance窗口上的属性来检测变化。该通知按预期发送,但是当我去更新颜色时,NSColor仍然给我深色模式颜色(或应用程序启动的任何模式)。例如,NSColor.textColor当我响应从暗模式切换到亮模式时,它仍然是白色而不是黑色。我自己的颜色资产似乎也发生了同样的情况。

我应该以不同的方式或时间获得这些颜色吗?或者这可能是一个操作系统错误?

编辑:如果 Web 视图的有效外观名称发生变化, 我还尝试创建一个子类WebView并更新我的颜色。drawRect()第一次,我得到所有浅色,即使应用程序在暗模式下启动也是如此。之后,当我从浅色模式切换到深色时,我会得到系统颜色的深色版本和资产目录颜色的浅色版本。

在调试器之外,切换到暗模式是可行的,但初始加载总是得到浅色。

4

2 回答 2

22

更改系统外观不会改变当前外观,您可以查询和设置,并且独立于系统外观。但外观实际上取决于“拥有”视图,因为在同一视图层次结构中,由于活力和手动设置appearance视图的属性,可能会出现几种外观。

Cocoa 已经在一些情况下更新了当前外观,例如在drawRect:、和. 在其他任何地方,您都应该这样做:updateLayerlayoutupdateConstraints

NSAppearance * saved = [NSAppearance currentAppearance];
[NSAppearance setCurrentAppearance:someView.effectiveAppearance];

// Do your appearance-dependent work, like querying the CGColor from
// a dynamic NSColor or getting its RGB values.

[NSAppearance setCurrentAppearance:saved];
于 2018-09-26T11:38:27.603 回答
3

DarkDust 提出的解决方案的 Swifty 版本:

extension NSAppearance {
    static func withAppAppearance<T>(_ closure: () throws -> T) rethrows -> T {
        let previousAppearance = NSAppearance.current
        NSAppearance.current = NSApp.effectiveAppearance
        defer {
            NSAppearance.current = previousAppearance
        }
        return try closure()
    }
}

你可以使用

NSAppearance.withAppAppearance {
    let bgColor = NSColor.windowBackgroundColor
    // ...
}

请注意,我正在从 NSApp 中出现,但它可能来自 NSWindow 或 NSView。

于 2020-09-12T10:55:24.787 回答