ハイライト
iPadOS 18 の PencilKit ツールバーがついにカスタムツールに対応——スタンプ、消しゴム、レタッチツールをシステムツールバーに直接配置でき、Apple Pencil Pro の squeeze、barrel roll、触覚フィードバックを自動取得。
主要内容
描画 app 開発者は長年選択を迫られてきた:PencilKit でツールバー体験は良いがツール種類はシステム内蔵(ペン、消しゴム、投げ縄)に限定。自前キャンバスとツールバーなら柔軟だが、squeeze、hover プレビュー、barrel roll など Apple Pencil Pro 機能をゼロから実装する膨大な工数。
今年 Apple は折衷案 PKToolPickerCustomItem を提示。カスタムツールを PencilKit ツールバーに登録し、ユーザーはシステムツールバーで切り替え可能。カスタムツール選択時、PencilKit キャンバスは自動で描画停止、コードがレンダリングを引き継ぐ。ツールバーのカラーピッカー、幅スライダーは引き続き使用可能。追加コントロール用に UIViewController を渡せる。barrel roll、squeeze などのインタラクションはカスタムツールで自動対応——追加コード不要。
Apple Pencil Pro は 3 つの新インタラクション能力を追加:squeeze ジェスチャ(軸を捏ねてトリガー)、barrel roll 角度(軸回転でストローク方向制御)、位置情報ベース触覚フィードバック(補助線整列や形状認識時の手触り)。PencilKit 内蔵ツールは自動対応。カスタムキャンバスは新 UIPencilInteraction、UICanvasFeedbackGenerator、SwiftUI の .onPencilSqueeze、.sensoryFeedback で統合可能。
詳細
ツールバーカスタマイズ:toolItems イニシャライザ
iOS 13 以降 PKToolPicker はデフォルト全ツールセットのみ。iPadOS 18 で toolItems イニシャライザ追加——ツールバーのツール順序と種類を指定(02:39)。同タイプ複数配置可能——赤ペン、青ペンなど。注釈 app に非常に有用。
ツールバー項目タイプ:PKInkingToolItem(インク)、PKEraserToolItem(消しゴム)、PKLassoToolItem(投げ縄)、PKRulerItem(定規、タップで切替)、PKScribbleItem(手書き→文字)、PKToolPickerCustomItem(カスタムツール)、末尾 UIBarButtonItem(非描画操作)(04:55)。
カスタムツール:PKToolPickerCustomItem
カスタムツールの核心は PKToolPickerCustomItem と Configuration 構造体(06:10)。Configuration がサポート属性を定義——色、幅、不透明度は PencilKit コントロール。追加属性は渡した UIViewController で表示。ツールアイコンはクロージャでレンダリング提供。色・幅・不透明度変更時 PencilKit が自動呼び出し。カスタム属性変更時は reloadImage() を手動呼び出し。
カスタムツール選択後、関連 PKCanvasView はすべて自動で描画停止。コードがタッチイベントとレンダリングを引き継ぐ。PencilKit はツール選択 UI のみ担当。
Squeeze ジェスチャ
Apple Pencil Pro の squeeze でペンを離さずツールバーやコンテキストパネルを表示(09:20)。グローバルシステム設定が squeeze の動作を決定:コンテキストパレット表示、ショートカット実行、カスタム動作。ユーザーがショートカットを選んだ場合、app は squeeze イベントを受信しない。
UIKit で squeeze に応答:
class MyViewController: UIViewController, UIPencilInteractionDelegate {
func pencilInteraction(_ interaction: UIPencilInteraction,
didReceiveSqueeze squeeze: UIPencilInteraction.Squeeze) {
if UIPencilInteraction.preferredSqueezeAction == .showContextualPalette &&
squeeze.phase == .ended {
let anchorPoint = squeeze.hoverPose?.location ?? myDefaultLocation
presentMyContextualPaletteAtPosition(anchorPoint)
}
}
}
UIPencilInteractionDelegateのpencilInteraction(_:didReceiveSqueeze:)が squeeze イベントを受信(10:24)preferredSqueezeActionでユーザーのシステム設定を確認squeeze.phase == .endedでジェスチャ終了時のみトリガー、重複応答を回避squeeze.hoverPose?.locationで squeeze 時のホバー位置を取得、パネル配置に使用
SwiftUI で squeeze に応答:
@Environment(\.preferredPencilSqueezeAction) var preferredAction
@State var contextualPalettePresented = false
@State var contextualPaletteAnchor = MyPaletteAnchor.default
var body: some View {
MyView()
.onPencilSqueeze { phase in
if preferredAction == .showContextualPalette, case let .ended(value) = phase {
if let anchorPoint = value.hoverPose?.anchor {
contextualPaletteAnchor = .point(anchorPoint)
}
contextualPalettePresented = true
}
}
}
@Environment(\.preferredPencilSqueezeAction)でシステム設定を読み取り(10:46).onPencilSqueeze修飾子が squeeze イベントを受信。phaseでジェスチャ段階を区別value.hoverPose?.anchorでホバーアンカーを取得、パネル表示位置に使用
触覚フィードバック:UICanvasFeedbackGenerator
Apple Pencil Pro 触覚フィードバックにキャンバス専用 2 タイプ追加:alignment(整列補助線)と pathComplete(パス完了)(11:36)。フィードバック API は位置情報入力が必要——システムがコンテキストに最適な方式を選択。
UIKit で使用:
class MyViewController: UIViewController {
@ViewLoading var feedbackGenerator: UICanvasFeedbackGenerator
override func viewDidLoad() {
super.viewDidLoad()
feedbackGenerator = UICanvasFeedbackGenerator(view: view)
}
func dragAlignedToGuide(_ sender: MyDragGesture) {
feedbackGenerator.alignmentOccurred(at: sender.location(in: view))
}
func snappedToShape(_ sender: MyDrawGesture) {
feedbackGenerator.pathCompleted(at: sender.location(in: view))
}
}
UICanvasFeedbackGenerator(view:)初期化時にキャンバス view を渡す(11:50)alignmentOccurred(at:)で線が補助線に整列した時に触覚フィードバックpathCompleted(at:)で形状認識完了、ストロークが整形状にスナップした時にフィードバック
SwiftUI で使用:
@State var dragAlignedToGuide = 0
@State var snappedToShape = 0
var body: some View {
MyView()
.sensoryFeedback(.alignment, trigger: dragAlignedToGuide)
.sensoryFeedback(.pathComplete, trigger: snappedToShape)
}
.sensoryFeedback(.alignment, trigger:)で trigger 値変更時に整列フィードバック(12:29).sensoryFeedback(.pathComplete, trigger:)で trigger 値変更時にパス完了フィードバック- 最も具体的なサブ view に修飾子を付けるとフィードバックがより正確
Barrel roll の角度
Apple Pencil Pro の barrel roll で軸回転がストローク角度を制御(08:04)。PencilKit の marker と fountain pen は内蔵対応。カスタムキャンバスは UITouch.rollAngle と UIHoverGestureRecognizer.rollAngle で角度読み取り。Apple は rollAngle と azimuth 角度を加算することを推奨——roll 非対応デバイスでは azimuth がフォールバック(13:32)。rollAngle は初期推定値で、Bluetooth 更新で精緻化——touchesEstimatedPropertiesUpdated で最終精密値を取得。
重要ポイント
-
何をするか:カスタム描画ツールを
PKToolPickerCustomItemに登録。価値:ユーザーがシステムツールバーで切り替え、squeeze と barrel roll が自動対応。インタラクションロジックを自前実装不要。始め方:PKToolPickerCustomItem.Configuration作成、色/幅属性定義、アイコンレンダリングクロージャ提供、toolItemsイニシャライザでツールバー構築。 -
何をするか:カスタムキャンバスに squeeze ジェスチャ統合、コンテキストツールパネル表示。価値:ペンを離さずツール切替やオプション表示——描画フロー中断なし。始め方:UIKit では
UIPencilInteractionDelegateのpencilInteraction(_:didReceiveSqueeze:)実装。SwiftUI では.onPencilSqueeze修飾子。preferredSqueezeActionを確認してシステム設定を尊重。 -
何をするか:形状認識と整列スナップ時に触覚フィードバックをトリガー。価値:視覚確認前にスナップ成功を感知——より自然な手触り。始め方:UIKit は
UICanvasFeedbackGeneratorでalignmentOccurred(at:)とpathCompleted(at:)呼び出し。SwiftUI は.sensoryFeedback(.alignment, trigger:)と.sensoryFeedback(.pathComplete, trigger:)。 -
何をするか:カスタムブラシツールで barrel roll 角度を読み取り、ストローク回転を制御。価値:実筆の軸回転を模倣し、デジタル描画を紙筆に近い手触りに。始め方:
UITouch.rollAngleから角度読み取り、azimuthAngleを加算して総回転値に。touchesEstimatedPropertiesUpdatedで最終精密値を更新。
関連セッション
- Build a spatial drawing app with RealityKit — RealityKit で空間描画 app をゼロから構築。低レベル mesh と texture API
- What’s new in SwiftUI — SwiftUI 新
.onPencilSqueezeと.sensoryFeedback修飾子の完全コンテキスト - What’s new in AppKit — macOS 端 hover とポインタインタラクションの新進展
- Create custom hover effects in visionOS — visionOS カスタム hover 効果の実装方法
- Catch up on accessibility in SwiftUI — SwiftUI 無障害要素とインタラクションの支援技術適応
コメント
GitHub Issues · utterances