总结
macOS 14 Sonoma 在“设置”->“辅助功能”->“显示”下添加了“文本大小”设置。这类似于 iOS 中已经存在相当长一段时间的“文本大小”设置。
许多 Apple 应用程序会根据此设置自动调整文本大小。这包括 Xcode、设置、Finder、邮件、便笺等。 Xcode 和“设置”等应用程序仅更改侧边栏中的文本,而其他应用程序则更改整个应用程序中的文本。
问题
我的问题是如何在我自己的 macOS 应用程序中响应此设置?
研究
我搜索了 AppKit 文档。我搜索过 WWDC 视频。我搜索过苹果开发者论坛。我见过没有提到这是如何完成的。
在这里我看到了:
NSTextField
。实验
我使用 AppKit 创建了一个本机 macOS 应用程序。我添加了一个
NSTextField
和一个 NSTextView
并将字体设置为文本样式,例如“Title 1”。更改设置不会自动更改应用程序中显示的字体大小。
我创建了一个 SwiftUI 应用程序并添加了本机 macOS 版本。我使用
ContentView
设置了一个 Text
和一些 Text("This is some text").font(.title)
。更改设置不会自动更改应用程序中显示的字体大小。
我有一个使用 Mac Catalyst 为 macOS 构建的 iOS 应用程序。当 iOS 设置应用程序中的“文本大小”设置更改时,iOS 版本的应用程序会自动调整其文本。在 macOS 设置应用程序中更改“文本大小”设置时,应用程序的 macOS 版本根本不会改变。
在本机 AppKit 应用程序中,我在
AppDelegate
中尝试了以下代码:
NSWorkspace.shared.notificationCenter.addObserver(forName: nil, object: nil, queue: nil) { note in
print(note)
}
NotificationCenter.default.addObserver(forName: nil, object: nil, queue: nil) { note in
print(note)
}
更改“文本大小”设置时,这些都不会生成任何输出。在 iOS/UIKit 下,您会收到
UIContentSizeCategory.didChangeNotification
通知。
作为一个盲目的尝试,我使用自己的自定义
NSApplication
子类设置了 AppKit 应用程序,并添加了以下内容:
class Application: NSApplication {
override func sendEvent(_ event: NSEvent) {
print("event \(event)")
super.sendEvent(event)
}
override func sendAction(_ action: Selector, to target: Any?, from sender: Any?) -> Bool {
print("action: \(action)")
return super.sendAction(action, to: target, from: sender)
}
}
更改“文本大小”设置时,这些都不会产生输出。
总结
我现在很茫然。需要哪些代码才能允许 macOS 应用程序响应“文本大小”设置的更改?我迫切需要的是使用 Mac Catalyst 为 macOS 构建的 iOS/UIKit 应用程序,但我对本机 AppKit 甚至 SwiftUI 中的解决方案很满意。代码可以是 Swift 或 Objective-C。
defaults
文本大小存储在
com.apple.universalaccess.plist
为 FontSizeCategory
:
$ defaults read com.apple.universalaccess FontSizeCategory
# {
# "com.apple.MobileSMS" = UseGlobal;
# "com.apple.Notes" = UseGlobal;
# "com.apple.finder" = UseGlobal;
# "com.apple.iBooksX" = UseGlobal;
# "com.apple.iCal" = UseGlobal;
# "com.apple.mail" = UseGlobal;
# "com.apple.news" = UseGlobal;
# "com.apple.stocks" = UseGlobal;
# "com.apple.weather" = UseGlobal;
# global = DEFAULT;
# version = "3.0";
# }
global
是我们感兴趣的。
以下是“设置”应用程序中可能的值和相应选项的列表:
价值 | 文字大小 | 侧边栏图标大小 |
---|---|---|
|
9分 | 小 |
|
10分 | 小 |
|
11分 | 小 |
|
12分 | 中 |
|
默认(11点) | 中 |
|
13分 | 中 |
|
14点 | 中 |
|
15分 | 大 |
|
16分 | 大 |
|
17分 | 大 |
|
20分 | 大 |
|
24点 | 大 |
|
29分 | 大 |
|
35点 | 大 |
|
42点 | 大 |
观察文字大小变化:
创建一个
UserDefaults
对象,套件名称为com.apple.universalaccess
。确保您对其保持强引用,否则您不会收到 KVO 回调。
使用 KVO 观察键
FontSizeCategory
的变化。
extension UserDefaults {
// I'm using `observe(_:options:changeHandler:)` below and it only accept
// a `KeyPath` key path, so this is required for this use case.
// Notice the the property name is the same as the key `FontSizeCategory`,
// because the property name is used as the KVO key.
@objc var FontSizeCategory: [String: Any]? {
dictionary(forKey: "FontSizeCategory")
}
}
let universalAccessDefaults = UserDefaults(suiteName: "com.apple.universalaccess")!
var fontSizeCategoryObservation: NSKeyValueObservation?
fontSizeCategoryObservation = universalAccessDefaults.observe(\.FontSizeCategory, options: .new) { [unowned self] _, changes in
guard let newValue = changes.newValue.flatMap(\.self), let global = newValue["global"] as? String else { return }
print(global)
/* Update your UI for text size change */
}
有人说这需要临时例外权利,并且 App Store 通常不允许。
不幸的是,我们在 macOS API 中还没有动态类型。像
NSFont.preferredFont(forTextStyle:)
这样的方法总是返回固定的字体大小。
目前,我们需要维护一个从 iOS 迁移的我们自己的字体大小列表。这是很多工作,而且我对排版几乎一无所知,所以我把这个留给你了。
以下是一些可能有用的链接: