WWDC Quick Look 💓 By SwiftGGTeam
Squeeze the most out of Apple Pencil

Squeeze the most out of Apple Pencil

元の動画を見る

ハイライト

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 内蔵ツールは自動対応。カスタムキャンバスは新 UIPencilInteractionUICanvasFeedbackGenerator、SwiftUI の .onPencilSqueeze.sensoryFeedback で統合可能。

詳細

ツールバーカスタマイズ:toolItems イニシャライザ

iOS 13 以降 PKToolPicker はデフォルト全ツールセットのみ。iPadOS 18 で toolItems イニシャライザ追加——ツールバーのツール順序と種類を指定(02:39)。同タイプ複数配置可能——赤ペン、青ペンなど。注釈 app に非常に有用。

ツールバー項目タイプ:PKInkingToolItem(インク)、PKEraserToolItem(消しゴム)、PKLassoToolItem(投げ縄)、PKRulerItem(定規、タップで切替)、PKScribbleItem(手書き→文字)、PKToolPickerCustomItem(カスタムツール)、末尾 UIBarButtonItem(非描画操作)(04:55)。

カスタムツール:PKToolPickerCustomItem

カスタムツールの核心は PKToolPickerCustomItemConfiguration 構造体(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)
        }
    }
}
  • UIPencilInteractionDelegatepencilInteraction(_: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.rollAngleUIHoverGestureRecognizer.rollAngle で角度読み取り。Apple は rollAngle と azimuth 角度を加算することを推奨——roll 非対応デバイスでは azimuth がフォールバック(13:32)。rollAngle は初期推定値で、Bluetooth 更新で精緻化——touchesEstimatedPropertiesUpdated で最終精密値を取得。

重要ポイント

  • 何をするか:カスタム描画ツールを PKToolPickerCustomItem に登録。価値:ユーザーがシステムツールバーで切り替え、squeeze と barrel roll が自動対応。インタラクションロジックを自前実装不要。始め方PKToolPickerCustomItem.Configuration 作成、色/幅属性定義、アイコンレンダリングクロージャ提供、toolItems イニシャライザでツールバー構築。

  • 何をするか:カスタムキャンバスに squeeze ジェスチャ統合、コンテキストツールパネル表示。価値:ペンを離さずツール切替やオプション表示——描画フロー中断なし。始め方:UIKit では UIPencilInteractionDelegatepencilInteraction(_:didReceiveSqueeze:) 実装。SwiftUI では .onPencilSqueeze 修飾子。preferredSqueezeAction を確認してシステム設定を尊重。

  • 何をするか:形状認識と整列スナップ時に触覚フィードバックをトリガー。価値:視覚確認前にスナップ成功を感知——より自然な手触り。始め方:UIKit は UICanvasFeedbackGeneratoralignmentOccurred(at:)pathCompleted(at:) 呼び出し。SwiftUI は .sensoryFeedback(.alignment, trigger:).sensoryFeedback(.pathComplete, trigger:)

  • 何をするか:カスタムブラシツールで barrel roll 角度を読み取り、ストローク回転を制御。価値:実筆の軸回転を模倣し、デジタル描画を紙筆に近い手触りに。始め方UITouch.rollAngle から角度読み取り、azimuthAngle を加算して総回転値に。touchesEstimatedPropertiesUpdated で最終精密値を更新。

関連セッション

コメント

GitHub Issues · utterances