认识 PaperKit
Meet PaperKit
2025年6月9日
一句话判断
PaperKit 把系统级的标记体验(Notes、截图、QuickLook 里的那个)开放给了第三方 App——画笔 + 形状 + 图片 + 文本框全在一个画布上,macOS Tahoe 也支持了。上手成本极低,但 FeatureSet 的定制和前向兼容性的处理才是真正拉开差距的地方。
这场 Session 讲了什么
PaperKit 是 Apple 自己的标记框架,之前只在系统 App 里用(Notes、截图、QuickLook、Journal)。现在第三方 App 可以直接集成。
三个核心组件:PaperMarkupViewController 是标记控制器,负责交互式创建和展示标记/PencilKit 绘画;PaperMarkup 是数据模型容器,处理保存/加载/渲染;MarkupEditViewController(iOS/iPadOS/visionOS)和 MarkupToolbarViewController(macOS)是元素插入 UI。
集成步骤极简:初始化 PaperMarkup(配置 bounds)-> 创建 PaperMarkupViewController(传入 FeatureSet)-> 加入视图层级 -> 配置 PencilKit Tool Picker。macOS 的区别只是插入 UI 用工具栏而非弹出菜单。
关键新功能:macOS Tahoe 原生支持 PaperKit;PencilKit 新增了书法笔(Reed 工具);HDR 支持(通过 colorMaximumLinearExposure 属性);FeatureSet.latest 自动获取最新功能;可以设置自定义背景视图(contentView)。
值得深挖的点
FeatureSet 的”latest”陷阱
FeatureSet.latest 给你所有最新功能,但这是双刃剑。如果 Apple 在后续系统版本往 latest 里加了新工具,你的 App 会自动获得这些工具——对大部分场景是好事。但如果你的 App 面向特定用户群体(比如教育、企业),你可能不想让新工具不受控地出现。建议的做法是:从 latest 出发,用 remove 去掉不需要的工具,而不是从空集用 insert 构建——这样未来的新工具默认可用,你可以根据需要选择性关闭。
另一个细节:FeatureSet 需要同时赋值给 PaperMarkupViewController 和 MarkupEditViewController/MarkupToolbarViewController。如果只给控制器没给插入 UI,用户可能看到工具却无法使用。
前向兼容性是硬性要求
Session 特别强调了版本检查。PaperMarkup 数据包含版本号,如果高版本系统创建的标记在低版本 App 里打开,可能会出现不兼容。最佳实践是在加载时检查 contentVersion,如果不匹配就显示预渲染的缩略图。
缩略图的生成方式:创建 CGContext -> 调用 PaperMarkup 的 draw 方法渲染到上下文 -> 保存缩略图。这是 Notes App 实际使用的方式。
HDR 标记的实现细节
HDR 效果通过 colorMaximumLinearExposure 控制。设成 1 是 SDR,大于 1 是 HDR。实际的 HDR 亮度取决于设备屏幕支持的 HDR headroom——可以用 UIScreen.main.maximumExtendedDynamicRangeColorComponentValue 获取屏幕支持的最大值。Session 的 demo 用了 4,效果比较好。
HDR 对 Reed 书法笔的效果提升很明显——笔触的渐变和光泽在 HDR 下更有层次感。
代码片段
iOS 基础集成
class MarkupViewController: UIViewController {
var markup: PaperMarkup!
var markupController: PaperMarkupViewController!
override func viewDidLoad() {
super.viewDidLoad()
// 初始化数据模型
markup = PaperMarkup(bounds: view.bounds)
// 创建标记控制器
let featureSet = FeatureSet.latest
markupController = PaperMarkupViewController(markup: markup,
featureSet: featureSet)
addChild(markupController)
view.addSubview(markupController.view)
markupController.didMove(toParent: self)
// 配置 PencilKit 工具选择器
let toolPicker = PencilKitToolPicker()
toolPicker.add(markupController)
// 工具选择器可见性控制
markupController.pencilKitResponderState.toolPickerVisibility = .visible
}
}
坑:PaperMarkup 的 bounds 必须和视图的 bounds 一致——不匹配会导致渲染偏移或裁切。
macOS 工具栏集成
// macOS 的区别是用工具栏而非弹出菜单
class MacMarkupViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let markup = PaperMarkup(bounds: view.bounds)
let featureSet = FeatureSet.latest
let markupController = PaperMarkupViewController(markup: markup,
featureSet: featureSet)
// macOS 用工具栏
let toolbar = MarkupToolbarViewController(featureSet: featureSet)
toolbar.delegate = markupController
// 标准视图控制器嵌入流程
addChild(markupController)
view.addSubview(markupController.view)
}
}
HDR + 自定义背景 + 前向兼容
// HDR 支持
var featureSet = FeatureSet.latest
featureSet.colorMaximumLinearExposure = 4.0
// 自定义背景(比如食谱模板)
let templateView = UIImageView(image: UIImage(named: "recipe_template"))
markupController.contentView = templateView
// 前向兼容处理
func loadMarkup(data: Data) {
do {
markup = try PaperMarkup(data: data)
} catch {
// 版本不兼容,显示缩略图
displayThumbnail(of: data)
}
}
func displayThumbnail(of data: Data) {
let context = CGContext(/* 配置 */)
let markup = PaperMarkup(data: data)
markup.draw(in: context!)
let thumbnail = UIImage(cgImage: context!.makeImage()!)
imageView.image = thumbnail
}
坑:draw 方法在版本不兼容时仍然可以工作——它会用支持的最高版本来渲染。但你不能编辑。
最佳实践
从 FeatureSet.latest 出发做减法。不要从空集开始逐个 insert——维护成本太高,而且会错过未来的新功能。用 remove 只去掉不适合你 App 的工具。如果你的 App 不需要 HDR 标记,就不要设 colorMaximumLinearExposure。
SwiftUI 集成用 UIViewControllerRepresentable 包装。PaperKit 的组件都是 UIKit 的,但封装后可以直接用在 SwiftUI 视图层级里。保持 UIKit 组件和 SwiftUI 布局的兼容性。
PencilKit Tool Picker 的新 API(pencilKitResponderState)可以控制工具选择器的可见性——即使隐藏了工具选择器,双击和挤压手势仍然有效。这对想要自定义工具栏 UI 的 App 非常有用。
还有什么值得关注
- PaperKit 支持的标记元素包括:自由绘画、形状(包括星星评分这类用法)、图片(支持拖放)、文本框等。
- Reed 书法笔是 PencilKit 的新工具,在 HDR 下效果最佳。
- PaperMarkup 的 delegate 提供了 markupChange 回调,可以在这里自动保存。另外 PaperMarkupViewController 实现了 Observable,也可以用 Observation 框架监听变化。
- SwiftUI 集成时,用 UIViewControllerRepresentable 包装后可以在 SwiftUI body 里直接使用,保留 UIKit 和 SwiftUI 两种框架的兼容性。
- macOS Tahoe 上 PaperKit 的体验和 iOS 一致——包括形状、图片、文本框等所有标记元素,Journal App 就是用 PaperKit 构建的。