
-
PaperKitの紹介
iOS、iPadOS、macOS、visionOSのアプリにPaperKitを導入する方法について説明します。図形や画像などのマークアップ機能をPencilKitの描画にシームレスに統合する方法、ユーザーインターフェイスをカスタマイズする方法、および将来の互換性を確保するためのベストプラクティスを紹介します。アプリに独自のマークアップ体験を追加するための高度なカスタマイズオプションについても説明します。
関連する章
- 0:00 - イントロダクション
- 1:36 - PaperKitの基本知識
- 3:35 - PaperKitの導入
- 8:37 - 機能セットのカスタマイズ
リソース
関連ビデオ
WWDC24
WWDC20
-
このビデオを検索
こんにちはPencil & Paperチームの エンジニアAndreeaです 本セッションではPaperKitを紹介します PaperKitフレームワークは Appleのシステム全体で 独自のマークアップ体験を提供します メモ、スクリーンショット、QuickLook ジャーナルなどのアプリで使えます
どのアプリでも簡単に 豊富なマークアップが行えます PaperKitには描画とさまざまな マークアップ要素を加えられる キャンバスがあります 要素には図形や画像 テキストボックスなどがあります 描画とマークアップ要素の両方を サポートしているPaperKitは すべてのアプリに加えるのに最適で 包括的なマークアップ体験を提供します
macOS Tahoeにも新しく加えられ 同じく豊富な マークアップ体験を提供するので どのmacOSアプリの描画と マークアップ要素もうまく機能します この新しいジャーナルアプリが その例です
最初にPaperKitの主な機能を紹介し 背後にあるコアコンポーネントを説明します
次にPaperKitマークアップを簡単に 皆さんのアプリに統合する方法
最後にPaperKitマークアップ体験を カスタマイズしてアプリの要件に 最も適した形にする方法を説明します
まず機能に焦点を当ててデモを行います すべてのレシピを管理して 変更を加えるたびに マークアップを使い更新できる アプリを作成しました レシピはすでに書いてあります 7歳の時から作っている 大好きな ルーマニア風クッキーで 星の数で評価も付けてあります レシピを完成させるために クッキーの画像を追加します ファイルアプリを開き
画像をレシピにドラッグします
見栄えを良くするために再配置します
またクルミ粉も大事な 材料であるためハイライトします
PaperKitで行えることを説明したので その3つの主要な構成要素を分解します 1つ目はPaperMarkupViewController というマークアップコントローラです PaperKitのマークアップと描画を インタラクティブに作成して表示します
2つ目はPaperMarkupと呼ばれる データモデルコンテナです PaperKitマークアップと PencilKit描画データの保存 および読み込みを処理し マークアップのレンダリングを処理します
3つ目は新しい挿入メニューで マークアップ要素を使って キャンバスに注釈を付けられます iOS、iPadOS、visionOS 26では MarkupEditViewControllerと呼ばれます
macOSでは代替オプションは MarkupToolbarViewControllerという 新しいツールバーで 描画ツールと注釈用のボタンが付いています
アプリにPaperKitを導入するのは簡単です 最初に iOSのレシピアプリに 統合した方法を説明します 次にmacOSでの手順について説明します
まずUIViewControllerを サブクラス化しました viewDidLoadメソッド内で マークアップデータモデルコンテナを 初期化しました ビューの境界に一致するように構成し 適切なレイアウトとレンダリング コンテキストを確保します 次にマークアップコントローラを作成します これはPaperKitが提供する 最新機能の完全セットで構成されています
それをビュー階層に追加しました これには標準ビューコントローラの 埋め込みプロセスを使用します
ツールピッカーを作成するには PencilKitツールピッカーを初期化し マークアップコントローラを オブザーバとして登録することで ツールピッカーの状態の変化に 動的に応答できるようにします
アプリ内にツールピッカーを表示するため PencilKitレスポンダ状態の activeToolPickerプロパティに割り当てました これはUIResponderで利用可能な 新しいAPIで 現在のレスポンダーのツールピッカーの 可視性を制御します toolPickerVisibilityプロパティを 構成することで ツールピッカーをアクティブにして 同時に画面上の可視性を 明示的に管理できます これによりツールピッカーは 非表示のまま完全に機能し ダブルタップやスクイーズジェスチャーなどの 操作にも反応し すべてのアプリがミニツールピッカー体験を サポートするようになります ツールピッカーの設定について詳しくは WWDC19の「Introducing PencilKit」と WWDC24の 「Squeeze the most out of Apple Pencil」を ご覧ください ツールピッカーを設定した後 アクセサリ項目をボタンとして構成しました タップすると挿入メニューを表示する 関数がトリガーされます
メソッド内で マークアップコントローラと同じ 機能セットを使用して 挿入コントローラを初期化しました
次にコントローラのデリゲートを マークアップビューコントローラに設定し それをポップオーバーとして 表示するように設定 次に適切な配置のために ツールピッカーに追加した バーボタン項目に ポップオーバーを固定しました
最後に挿入メニューコントローラを モーダルで提示しました
macOSでの導入も同じように簡単です
マークアップモデルとマークアップ コントローラの設定は基本的に同じです
macOSでの唯一の違いは ツールバーを作成し 挿入UIを表示できることです そこからツールバーのデリゲートを マークアップコントローラに設定し それをビュー階層に追加しますが これには標準NSViewControllerの 埋め込みプロセスを使用します
基本設定が完了したので ここでアプリ体験の改良に 不可欠な いくつかの重要な要素を検討します
PaperKitはSwiftUI環境に シームレスに統合します コンポーネントは UIViewControllerRepresentable内に カプセル化され これがさらに SwiftUIビューの本体に直接組み込まれます これによりUIKitベースの コンポーネントが SwiftUIレイアウト内で使用でき両方の フレームワーク間の互換性が維持されます ビューコントローラをSwiftUI環境に 統合する方法の詳細は WWDC20の「What’s New in SwiftUI」 をご確認ください
マークアップコントローラには デリゲートが含まれ これによりコールバックの カスタム処理が可能になります たとえばマークアップ変更デリゲート メソッドを実装し マークアップモデルへの変更を 自動的に保存できます さらにマークアップコントローラは Observableに準拠していて デリゲート以外の方法で 状態および更新を 管理できます
ディスクからデータを読み込む場合 前方互換性のために コンテンツバージョンを常に 検証することが不可欠です バージョンの不一致を処理するには 一般的に次の2つの方法があります アップグレードの必要性を 知らせるアラートの提示か マークアップの事前レンダリングされた サムネールの表示です
PaperKitは前方互換性を非常に 簡単にするためのツールを提供します まずサムネールをレンダリングする CGContextを作成します
次にマークアップモデルの 描画関数を使用して モデルのサムネール画像を生成し
最後にマークアップと一緒に保存します
バージョンが一致しない場合に このサムネールを表示することが ベストプラクティスと考えられ これがまさにメモのようなアプリが 使用しているものです
iOSとmacOSの両方における PaperKitの導入の説明でした 次は思い通りのマークアップ体験を 提供するためアプリを カスタマイズする方法です PaperKitで使用可能な すべてのマークアップの機能セットは FeatureSetと呼ばれます マークアップコントローラと挿入 コントローラの両方に公開される 機能とツールを定義します
FeatureSet.latestは PaperKitがサポートするマークアップ機能の 完全なセットを提供します これはフレームワークに追加された 新機能の最新情報を入手する ための出発点として最適です
マークアップ体験をカスタマイズするには remove関数とinsert関数 を使用できます これによりアプリで 使えるツールや インタラクションを 完全に制御できます
HDRサポートをマークアップで 有効にするには 機能セットのcolorMaximumLinearExposure プロパティを 1より大きい数値に設定します SDRマークアップの場合は 1を使用します HDRインクにはこのプロパティを ツールピッカーでも設定します 私のアプリでは4で 希望のHDR効果が得られました
colorMaximumLinearExposure で設定する値は デバイスの画面でサポートされている HDRヘッドルームに トーンマッピングされます または画面でサポートされている値を 使用します これはUIScreenまたは NSScreenから取得できます
最新の機能セットを使用し アプリでHDRを有効にすることで すべての新機能と体験を 手に入れることができます たとえばカリグラフィーの新しいツール ReedがPencilKitに
導入されましたが これはHDRに最適です
機能セットが要件に 合わせて構成されたら カスタマイズした機能セットをマークアップ コントローラと挿入コントローラの 両方に割り当てて アプリのマークアップと挿入の機能 全体で一貫性を確保します
もう1つのカスタマイズ可能なプロパティは マークアップコントローラのcontentViewで これは任意のUIViewに設定できます たとえばテンプレートをアプリの フィクスチャとして使用できます すべてのマークアップと描画は その上にレンダリングされます FeatureSetをカスタマイズし 背景ビューを構成し 前述した改良のステップを適用することで 皆さんのアプリも同じように強力かつ創造的に カスタマイズされた素晴らしいマークアップ 体験をシステム全体で提供できます
次のステップです Appleのパワフルな マークアップ体験を取り入れ 独自のツールとインクを使用して FeatureSetをカスタマイズし 独自のコンテンツ背景を設定し マークアップにHDRサポートを追加します
軽量のメモツールを 作るのか 豊富で創造的なキャンバスを 作るのかを問わず PaperKitは完璧な体験を 作り出すツールを提供します 皆さんがPaperKitでどんなアプリを 作るのかとても楽しみです
ありがとうございました
-
-
3:47 - Adopt PaperKit in iOS
// Adopt PaperKit in iOS override func viewDidLoad() { super.viewDidLoad() let markupModel = PaperMarkup(bounds: view.bounds) let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest) view.addSubview(paperViewController.view) addChild(paperViewController) paperViewController.didMove(toParent: self) becomeFirstResponder() let toolPicker = PKToolPicker() toolPicker.addObserver(paperViewController) pencilKitResponderState.activeToolPicker = toolPicker pencilKitResponderState.toolPickerVisibility = .visible toolPicker.accessoryItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(plusButtonPressed(_:))) } @objc func plusButtonPressed(_ button: UIBarButtonItem) { let markupEditViewController = MarkupEditViewController(supportedFeatureSet: .latest) markupEditViewController.delegate = paperViewController markupEditViewController.modalPresentationStyle = .popover markupEditViewController.popoverPresentationController?.barButtonItem = button present(markupEditViewController, animated: true) }
-
6:11 - Adopt PaperKit in macOS
// Adopt PaperKit in macOS override func viewDidLoad() { super.viewDidLoad() let markupModel = PaperMarkup(bounds: view.bounds) let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest) view.addSubview(paperViewController.view) addChild(paperViewController) // Create toolbar for macOS let toolbarViewController = MarkupToolbarViewController(supportedFeatureSet: .latest) toolbarViewController.delegate = paperViewController view.addSubview(toolbarViewController.view) // Set layout setupLayoutConstraints() }
-
7:18 - Auto-save markup changes
// Auto-save markup changes func paperMarkupViewControllerDidChangeMarkup(_ paperMarkupViewController: PaperMarkupViewController) { let markupModel = paperMarkupViewController.markup Task { // Create a data blob and save it let data = try await markupModel.dataRepresentation() try data.write(toFile: paperKitDataURL) } }
-
8:02 - Thumbnail for forward compatibility
// Thumbnail for forward compatibility func updateThumbnail(_ markupModel: PaperMarkup) async throws { // Set up CGContext to render thumbnail in let thumbnailSize = CGSize(width: 200, height: 200) let context = makeCGContext(size: thumbnailSize) context.setFillColor(gray: 1, alpha: 1) context.fill(renderer.format.bounds) // Render the PaperKit markup await markupModel.draw(in: context, frame: CGRect(origin: .zero, size: thumbnailSize)) thumbnail = context.makeImage() }
-
9:02 - Customized markup FeatureSet
// Customized markup FeatureSet var featureSet: FeatureSet = .latest featureSet.remove(.text) featureSet.insert(.stickers) // HDR support featureSet.colorMaximumLinearExposure = 4 toolPicker.colorMaximumLinearExposure = 4 let paperViewController = PaperMarkupViewController(supportedFeatureSet: featureSet) let markupEditViewController = MarkupEditViewController(supportedFeatureSet: featureSet)
-
10:50 - Custom background on markup controller
// Custom background on markup controller let template = UIImage(named: "MyTemplate.jpg") let templateView = UIImageView(image: template) paperViewController.contentView = templateView
-