-
PaperKitの詳細
PaperKitを利用するとキャンバスベースのアプリを作成できます。マークアップ要素へのアクセス、作成、編集を可能にする、データモデルに関する新しいAPIを確認しましょう。カスタムのコントロールや注釈を追加する方法と、これらの機能をアプリに統合してフル機能のクリエイティブキャンバスを構築する際のベストプラクティスを紹介します。
関連する章
- 0:00 - Introduction
- 1:22 - Data model
- 3:41 - Elements
- 5:17 - Adornments
- 7:11 - Next steps
リソース
関連ビデオ
WWDC26
WWDC25
-
このビデオを検索
こんにちは Pencil and Paperチームの エンジニア、Mattです。 ユーザーが自由に作成できる キャンバスを提供するアプリは Appleプラットフォームで最も象徴的で 力強い体験の1つです。 PaperKitはキャンバス体験を 実現するフレームワークで Appleの多くのアプリで 利用されています。 アイデアをスケッチしたり 画像を追加したりするとき メモでドキュメントに 注釈を付けるのもPaperKitです。 ペン、図形、テキスト、画像など フルキャンバス体験を提供します すべてが連携して動作します。 プレビューでPDFを開いて署名を追加したり テキストをハイライトしたりするとき 重要な箇所を丸で囲むのも PaperKitです。
macOSのフリーボードでアイデアを 出すのもPaperKitです。
iOS、macOS、visionOS 27では PaperKitが広く使えるようになります。 今日はPaperKitを活用する 方法をご紹介します キャンバス体験を完全に 制御できるようになります。
まずデータモデルから 始めます。 キャンバス上のすべての要素に アクセスできます。
次に図形や画像などの エレメントの操作を紹介します。
最後はアドーンメントです。 インタラクティブなオーバーレイや コントロールを追加できます。
データモデルから始めましょう。 PaperKitを使った コミックエディタを制作しています。 基本的なテンプレートは すでに設定してあります。 でも、ここまでしか できていませんでした。 このテンプレートを PaperMarkupに変換します。 PaperMarkupには新しい subelementsプロパティがあります。 キャンバス上のすべてのエレメントに MarkupOrderedSetとしてアクセスできます。 読み書きができる 順序付きコレクションです。 このコードは各パネルの 図形エレメントを作成します。
そしてマークアップを更新します。
以上です。 iPadで試してみましょう。
コミックに3コマのページを 追加します。 いい感じです。 思い通りに表示されています。 キャンバスは完全にインタラクティブですが コミックエディタでは 問題になります。 パネルを選択したり ドラッグ、削除もできてしまいます。
それは望ましくありません。 テンプレートのエレメントは 編集不可にする必要があります。 修正するには図形エレメントの 動作を変更します。
キャンバス上のすべてのエレメントは Markupプロトコルに準拠しています。
frameやrotationなど 共通プロパティが利用できます。
新しいallowedInteractionsプロパティも あります。 これはMarkupInteractionsの オプションセットです。 各エレメントで変更できる内容を 細かく制御できます。 移動、リサイズ、回転を 制御できます 削除、スタイル変更、選択も 個別または任意の組み合わせで設定できます。 すべてを一度に ロックしたい場合は read-onlyですべてを 1つのフラグにまとめられます コミックテンプレートに最適です。
コミックエディタのパネルへの インタラクションを制限するには .allowedInteractionsを .readOnlyに設定します。 試してみましょう。 パネルの境界線をタップすると 何も起きません。 テンプレートの図形は 読み取り専用です。 吹き出しを追加して 移動させることもできます
スタイルも変更できます
でもパネルは固定されたままです。 完璧です。 アプリが形になってきましたが パネルをもっと目立たせたいです テンプレートのスタイリング用に ツールバーにカラーピッカーを追加しました。
スタイリングを実装するために エレメントを詳しく見ます。 PaperMarkupの各エレメントには 具体的な型があります。
図形、画像、リンク、ルーペ、 ペンシルストロークです。 これらはすべて同じMarkupの 順序付きセットに含まれます Markupプロトコルに準拠しています。 ただし各型には 独自のカスタムプロパティがあります。 図形についてもっと詳しく見ましょう。 PaperKitは多くの図形タイプを サポートしています 各タイプには丸角矩形の cornerRadiusなど固有のプロパティがあります または曲線のcontrolPointsなどです。
コミックのパネルには 矩形を使いました。 strokeColorがあり これが目的のものです。 パネルに色を適用するには subelementsをイテレートします。
strokeとfillのカラーを設定します。
一段と目立たせるために マークアップの背景に 同じ色を使います。 最後にpaperMarkupViewControllerの マークアップを更新します。 iPadで結果を確認してみましょう。
するとキャンバスが 一変します。 選んだ色でページが スタイリングされます より個性的な作品へと 変わっていきます。 PaperKitはPencilKitの上に構築されており Apple Pencilで描くことができます。
各ストロークがマークアップの エレメントになります PencilKitのモデルAPIが すべて使えます。 これらのAPIは文字認識を サポートするようになりました Bézierパス変換にも 対応しています。 詳細については 「Reading Between the Strokes with PencilKit」をご覧ください。
次はアドーンメントを使った カスタムコントロールの追加を見ます。 各パネルにアートワーク作成用の ボタンを追加したいです。 でもそれらのコントロールを ドキュメントの一部にしたくありません。 保存、印刷、エクスポートの 対象外にしたいのです。 編集中だけキャンバスの上に 表示させたいです。 これがまさにMarkupの アドーンメントです キャンバス座標に固定された ビジュアルオーバーレイです。 ボタン、注釈、コラボレーションUIに 最適です。 ズームとスクロールを 自動的に追従します 永続化されたマークアップとは 完全に分離されています。 各パネルにMarkupAdornmentを 作成します。 パネルの中央に固定します imageConfigurationでSF Symbol アイコンを設定します。
配列をコントローラーの adornmentsプロパティに割り当てます。
タップを処理するには デリゲートメソッド didTapAdornmentWithIDを実装します。
ユーザーがアドーンメントをタップすると ImagePlaygroundViewControllerを 表示します。
Image Playgroundから画像が返ると ImageMarkupを作成します。
subelementsに挿入して ビューコントローラーのマークアップを更新します。 もう一度試してみましょう。
パネルをタップして アートワークを作成します。
コミックの主人公は スーパーヒーロードッグです 街で犯罪と戦っています。
生成された画像が パネルを埋めます。
アプリで画像を生成する 詳細については 「Create high-quality images using Image Playground」をご覧ください。 あと数枚の画像と テキスト、フォントを追加するだけで コミックの第1ページが完成しました。
スーパーヒーロードッグが 世界を救います。 これで完全にインタラクティブな キャンバスベースの体験を PaperKitで実装できます。 データモデルを使ってキャンバスの内容を プログラムで読み書きします。 アドーンメントを追加して アプリ専用のオーバーレイを作成します。 皆さんが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.