一个用于简化 macOS 外观值并检测设置更改的类 (Swift/Objective-C)。
支持 macOS 10.11 及更高版本,并在较旧的系统上提供合理的后备方案,以减少代码中的 #available/@available
检查。
如果在 macOS 应用程序中执行自定义绘图,请务必在执行绘图时遵守用户的显示和辅助功能设置,以便进行相应的调整。
DSFAppearanceManager
具有许多属性来简化 macOS 外观设置。
以下是 DSFAppearanceManager
上可用的静态属性。
属性 | 描述 |
---|---|
IsDark |
UI 当前是否以深色显示 |
IsDarkMenu |
菜单和 Dock 当前是否以深色显示 |
AccentColor |
当前强调色 |
HighlightColor |
当前高亮颜色 |
AquaVariant |
当前的 Aqua 变体 |
IncreaseContrast |
用户的“增加对比度”辅助功能设置 |
DifferentiateWithoutColor |
用户的“不使用颜色区分”辅助功能设置 |
ReduceTransparency |
用户的“减少透明度”辅助功能设置 |
InvertColors |
用户的“反转颜色”辅助功能设置 |
ReduceMotion |
用户的“减少动态效果”辅助功能设置 |
AutoplayAnimatedImages |
用户的“自动播放动画图像”辅助功能设置 (macOS 14+) |
因此,例如,要获取当前 macOS 的高亮颜色,请调用 DSFAppearanceManager.HighlightColor
。
您可以请求在外观设置更改时收到通知。当外观更改时,macOS 会自动调用某些方法:-
updateLayer
drawRect(dirtyRect: NSRect)
layout
updateConstraints
updateViewConstraints
viewWillLayout
viewDidLayout
但在某些情况下,您需要自己管理此操作。 这就是使用 ChangeDetector
类的地方。
声明一个 DSFAppearanceManager.ChangeDetector()
类型的变量
private let appearanceChangeDetector = DSFAppearanceManager.ChangeDetector()
...并设置回调块。 请注意,保证此回调在主线程上调用。
appearanceChangeDetector.appearanceChangeCallback = { [weak self] change in
// Handle the change here.
// `change` contains the _types_ of change(s) that occurred. This might be theme, accent, contrastOrAccessibility etc
let currentHighlightColor = DSFAppearanceManager.HighlightColor
...
}
change 对象指示发生的更改类型。
更改类型 | 描述 |
---|---|
theme |
系统外观(例如,深色/浅色)已更改 |
accent |
用户更改了强调色(例如,强调色/高亮色) |
aquaVariant |
对于较旧的 macOS 版本,变体(蓝色、石墨色) |
systemColors |
用户更改了系统颜色 |
finderLabelColorsChanged |
用户更改了 Finder 标签颜色 |
accessibility |
辅助功能显示设置已更改 |
autoplayAnimatedImages |
自动播放动画图像已更改 |
请注意,更改检测类会对更改进行去抖动,以减少发生更改时的回调次数。 回调块中传递的 change
对象包含发生的一组更改。
@interface ViewController ()
@property(nonatomic, strong) DSFAppearanceManagerChangeDetector* detector;
@end
@implementation ViewController
- (void)viewDidAppear {
[super viewDidAppear];
[self setDetector: [[DSFAppearanceManagerChangeDetector alloc] init]];
[[self detector] setAppearanceChangeCallback:^(DSFAppearanceManagerChange * _Nonnull change) {
// Change detected! Do something to update display
}];
}
@end
如果您有很多需要更新的小类,那么将更改通知集中在一个公共位置可能更有效。
该库提供了一个默认的全局(懒加载)DSFAppearanceCache.shared
对象实例供您使用,或者您可以自己创建和管理一个。
外观缓存提供了两种接收外观更新通知的机制。
您可以通过使您的对象符合 DSFAppearanceCacheNotifiable
协议来注册一个对象以接收外观更新。 该对象在缓存对象中被弱引用。
class LevelGauge: CustomLayer, DSFAppearanceCacheNotifiable {
init() {
DSFAppearanceCache.shared.register(self)
}
deinit {
DSFAppearanceCache.shared.deregister(self)
}
func appearanceDidChange() {
// Update the object
}
}
更改中心对象 DSFAppearanceCache
在 NotificationCenter.default
上生成通知。
通知名称: DSFAppearanceCache.ChangeNotificationName
您可以使用标准的 addObserver
机制注册通知。
self.observer = NotificationCenter.default.addObserver(
forName: DSFAppearanceCache.ChangeNotificationName,
object: DSFAppearanceCache.shared,
queue: OperationQueue.main) { _ in
// Do something with the change
}
确保你的 'appearanceDidChange' 中的代码快速执行!
DSFAppearanceManager
提供了 NSView
的扩展,以方便自动处理视图的有效绘制外观。
func drawRect(_ dirtyRect: CGRect) {
...
self.usingEffectiveAppearance {
// Requests for dynamic colors etc. within the block will automatically use the correct appearance for the view.
}
}
如果您无法使用 Assets.xcassets
来存储您的动态 NSColor
s(或者您想将应用程序的配置移到代码中),您会发现默认的 NSColor
对自动处理浅色/深色模式更改的支持不多。
Dusk 是一个小型 Swift 框架,旨在帮助支持 macOS 上的深色模式。 它提供了一个 NSColor
子类 (DynamicColor
),该子类在需要时自动提供浅色/深色模式变体。
lazy var c1 = DynamicColor(name: "uniqueColorName") { (appearance) in
// return the color to use for this appearance
}
let c1 = DynamicColor(name: "uniqueColorName", lightColor: NSColor.white, darkColor: NSColor.black)
并且因为 DynamicColor
继承自 NSColor
,所以可以在任何可以使用 NSColor
的地方使用它。
ChimeHQ
开发了出色的 动态 NSColor 子类。
MIT License
Copyright (c) 2023 Darren Ford
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.