-
深入探索 PaperKit
使用 PaperKit 制作基于画布的应用程序。探索新的数据模型 API,以便访问、创建和修改标记元素。了解如何添加自定控件和注释,并探索将这些功能整合到 App 中的最佳做法,打造功能齐全的创意画布。
章节
- 0:00 - Introduction
- 1:22 - Data model
- 3:41 - Elements
- 5:17 - Adornments
- 7:11 - Next steps
资源
相关视频
WWDC26
WWDC25
-
搜索此视频…
你好 我是Matt Pencil and Paper团队的工程师 能让用户在画布上 随心创作的App 是Apple平台上 最具代表性的体验之一 PaperKit正是驱动 画布体验的核心 支撑着Apple众多 自家应用程序的运行 当你手绘想法 插入图片 或在备忘录中标注文稿 那就是PaperKit 这是完整的画布体验 铅笔 形状 文字 图片 协同运作 当你在预览中打开PDF 添加签名或高亮段落 或圈出重要内容 那也是PaperKit
在macOS的Freeform中构思 同样是PaperKit
在iOS macOS和visionOS 27中 PaperKit全面开放 今天我将展示如何解锁PaperKit 让你完全掌控 你的画布体验
我将从数据模型入手 它让你访问 画布上的所有内容
然后介绍如何使用 形状和图片等元素
最后讲解装饰 用于添加交互式 覆盖层和控件
我们先来看数据模型 我一直在构建 一个基于PaperKit的漫画编辑器 我已设置了一些基本模板 但目前只到这一步 现在我需要将这些模板 转换为PaperMarkup PaperMarkup新增了 subelements属性 它让你以MarkupOrderedSet的形式 访问画布上的每个元素 这是一个有序集合 支持读取和写入 此代码段为每个面板 创建一个形状元素
然后更新markup
就这样 让我们在iPad上试试
我将为漫画添加 一个三页面板 很好 完全符合我的预期 画布完全可交互 但这对漫画编辑器 来说是个问题 我可以选中面板 拖动甚至删除它们
这不是我想要的 模板元素 不应该是可编辑的 要解决这个问题 我需要改变形状元素的行为
画布上的每个元素 都遵循Markup协议
这提供了通用属性 例如frame和rotation
还有一个新的 allowedInteractions属性 这是一个MarkupInteractions选项集 让你精细控制 每个元素可修改的内容 Markup interactions让你控制 移动 调整大小和旋转 以及删除 样式和选择 可单独或组合使用 如果你想一次性 锁定所有内容 read-only将所有内容 合并为单个标志 非常适合漫画模板
要限制漫画编辑器中 面板的交互 我需要将.allowedInteractions 设为.readOnly 我来试试 现在当我点击面板边框时 什么都没发生 模板形状已变为只读 我可以添加对话气泡 并移动它
并为其设置样式
但面板保持固定 完美 App开始成形 但面板需要更加突出 所以我在工具栏添加了 颜色选取器来设置模板样式
为了实现样式设置 我将深入研究元素 PaperMarkup中的每个元素 都有具体类型
形状 图片 链接 放大镜和铅笔笔触 它们都属于同一个 Markup有序集合 并遵循Markup协议 但每种类型 都有其自定义属性 让我们深入了解形状 PaperKit支持多种形状类型 每种类型都有其属性 例如圆角矩形的圆角半径 或曲线的控制点
我为漫画面板使用了矩形 它们有描边颜色 这正是我们需要的 要为面板应用颜色 我需要遍历subelements
然后设置描边和填充颜色
为了增添额外亮点 我将对markup背景 使用相同的颜色 最后在paperMarkupViewController上 更新markup 让我在iPad上查看结果
就这样 画布完成了变换 页面以我选择的颜色 进行了样式设置 开始展现出 更具个性的面貌 PaperKit基于PencilKit构建 我可以用Apple Pencil绘图
每个笔触都成为markup元素 我可以使用 所有PencilKit模型API 这些API现在支持 字符识别 和贝塞尔路径转换 想了解完整详情 请观看"Reading Between the strokes with PencilKit"
现在来看如何使用 装饰添加自定义控件 我想为每个面板添加按钮 让用户创建艺术作品 但我不希望这些控件 成为文稿的一部分 它们不应被保存 打印或导出 我希望它们仅在编辑时 显示在画布顶部 这正是Markup adornments的作用 锚定到画布坐标的 视觉覆盖层 这使adornments非常适合 按钮 注释和协作UI 它们自动跟踪缩放和滚动 与持久化的markup 完全分离 对于每个面板 我创建一个MarkupAdornment 我将它锚定到面板中心 并通过imageConfiguration 赋予它SF Symbol图标
然后将数组分配给 控制器的adornments属性
为了处理点击 我实现了代理方法 didTapAdornmentWithID
当用户点击adornment时 我会呈现 ImagePlaygroundViewController
当Image Playground返回图片时 我创建一个ImageMarkup
然后将其插入subelements 并更新视图控制器的markup 让我们再试一次
我将点击其中一个面板 来创建艺术作品
我的漫画将讲述 一只超级英雄狗 在城市中打击犯罪
生成的图片填满了面板
想进一步了解 在App中生成图片 请观看"Create high-quality images using Image Playground" 再添加几张图片 一些文字和字体 漫画第一页就完成了
我们的超级英雄狗 将拯救这一天 现在你可以构建 完全交互式的 基于画布的体验 在你的App中使用PaperKit 使用数据模型以编程方式 读取和修改画布上的内容 添加adornments以创建 专为App定制的交互式覆盖层 我迫不及待想看看 你们将如何解锁PaperKit 感谢收看!
-
-
1:36 - Creating markup subelements
import PaperKit func generateMarkup(pageSize: CGSize, panelFrames: [CGRect], configuration: ShapeConfiguration) -> PaperMarkup { var markup = PaperMarkup(bounds: CGRect(origin: .zero, size: pageSize)) var subelements: MarkupOrderedSet = markup.subelements for panelFrame: CGRect in panelFrames { let shape = ShapeMarkup(frame: panelFrame, configuration: configuration) subelements.append(shape) } markup.subelements = subelements return markup } -
3:03 - Making template elements read-only
import PaperKit func generateMarkup(pageSize: CGSize, panelFrames: [CGRect], configuration: ShapeConfiguration) -> PaperMarkup { var markup = PaperMarkup(bounds: CGRect(origin: .zero, size: pageSize)) var subelements: MarkupOrderedSet = markup.subelements for panelFrame: CGRect in panelFrames { var shape = ShapeMarkup(frame: panelFrame, configuration: configuration) shape.allowedInteractions = .readOnly subelements.append(shape) } markup.subelements = subelements return markup } -
4:22 - Apply style to template elements
import PaperKit func updatePanelColor(_ selectedColor: CGColor) { guard var markup: PaperMarkup = paperMarkupViewController.markup else { return } var subelements: MarkupOrderedSet = markup.subelements for element in subelements { guard var shape = element as? ShapeMarkup else { continue } shape.strokeColor = selectedColor shape.fillColor = selectedColor.copy(alpha: 0.15) subelements.updateOrAppend(shape) } markup.subelements = subelements markup.backgroundColor = selectedColor.copy(alpha: 0.15) paperMarkupViewController.markup = markup } -
5:53 - Add adornments to each panel
import PaperKit func addPanelAdornments(for page: Page) { var adornments: [MarkupAdornment] = [] for (panelIndex, panel) in page.panels.enumerated() { let adornmentID = UUID() adornmentPanelMapping[adornmentID] = panelIndex let center = CGPoint(x: panel.midX, y: panel.midY) let adornment = MarkupAdornment( id: adornmentID, anchor: .canvas(location: center), imageConfiguration: .systemImage("photo.badge.plus"), dragRegion: .fixed, scalesWithZoom: false ) adornments.append(adornment) } paperMarkupViewController.adornments = adornments } -
6:08 - Handle adornment taps
import ImagePlayground import PaperKit func paperMarkupViewController(_ paperMarkupViewController: PaperMarkupViewController, didTapAdornmentWithID id: UUID) { guard let panelIndex = adornmentPanelMapping[id] else { return } activeImageGenerationPanelIndex = panelIndex let imagePlaygroundViewController = ImagePlaygroundViewController() imagePlaygroundViewController.delegate = self present(imagePlaygroundViewController, animated: true) } -
6:20 - Place the generated image
import ImagePlayground import PaperKit func imageViewController(_ imageViewController: ImagePlaygroundViewController, didCreateImageAt imageURL: URL) { guard let panelFrame = activeGenerationPanelFrame, let paperMarkupViewController = pageViewController.paperViewController, var markup = paperMarkupViewController.markup, let image = UIImage(contentsOfFile: imageURL.path) else { return } let imageMarkup = ImageMarkup(frame: panelFrame, image: image) markup.subelements.append(imageMarkup) paperMarkupViewController.markup = markup }
-
-
- 0:00 - Introduction
Meet PaperKit, the canvas behind Notes, Preview, and Freeform, now open to your apps in iOS, macOS, and visionOS 27 — covering the data model, elements, and adornments.
- 1:22 - Data model
PaperMarkup's new subelements property exposes every canvas element as a readable, writable ordered set, and allowedInteractions gives fine-grained control over what each element permits.
- 3:41 - Elements
Each element has a concrete type — shapes, images, links, loupes, and pencil strokes — with its own properties, and PaperKit builds on PencilKit so Apple Pencil strokes become markup elements.
- 5:17 - Adornments
Markup adornments are visual overlays anchored to canvas coordinates — ideal for buttons, annotations, and collaboration UI — that track zoom and scroll and stay separate from persisted markup.
- 7:11 - Next steps
Building a fully interactive canvas experience with PaperKit — using the data model to read and modify canvas contents, and adding adornments for interactive overlays tailored to your app.