WWDC Quick Look 💓 By SwiftGGTeam
Meet Scribble for iPad

Meet Scribble for iPad

元の動画を見る

ハイライト

iPadOS 14はシステムレベルのApple Pencil手書き認識機能Scribbleを導入し、ユーザーは直接UITextFieldUITextViewまたはUISearchBar手書きで書き、システムによってリアルタイムにテキストに変換されます。


主要内容

以前は、Apple Pencil を使用して iPad にテキストを入力するときに、最初にテキスト ボックスをクリックし、次にキーボードまたは別の手書き領域に切り替えるという分割プロセスに遭遇することがよくありました。フォーム、検索ボックス、リマインダー リストなどのインターフェイスの場合、この手順により Pencil の継続的な操作が中断されます。 Pencil を手に持つと、ユーザーは頻繁にタッチとキーボードのロジックに戻る必要があります。

Scribble により、手書き認識が iPadOS 14 のシステム入力機能になります。ユーザーが編集可能なテキスト領域に直接書き込むと、システムがデバイス上の手書きを認識し、結果を既存のテキスト入力システムに渡します。標準の UIKit テキスト コントロール、標準の WebKit 編集可能要素、および Web フォームは、オートフィル経由で入力することが推奨されるパスワード フィールドを除き、デフォルトで使用できます。

開発者が本当に介入する必要があるのは、テキスト エクスペリエンスのカスタマイズです。カスタム テキスト エディターを完全に実装する必要があるUITextInput、Scribble がコンテンツを読み取り、範囲を選択し、テキストを変更するとき。カスタマイズされたキャンバス、編集可能になるクリック可能な領域、フォーカスに合わせて移動する検索ボックスを使用する必要があります。UIScribbleInteractionまたはUIIndirectScribbleInteractionどこに書き込めるか、いつ書き込めるか、書き込み後にどのレスポンダーに注目すべきかをシステムに伝えます。

このセッションの核心は複雑ではありません。標準のテキスト コントロールを使用してみてください。カスタマイズが必要な場合は、安定したレイアウトと十分な書き込みスペースを必要とする入力デバイスとして Pencil を設計します。

詳細

システムはデフォルトで標準のテキスト コントロールをサポートします

(06:12) Scribble は既存の iOS テキスト入力 API に依存しています。UITextFieldUITextViewUISearchBarこのような UIKit 標準コントロール、WebKit の標準の編集可能なコンテンツおよび Web フォームは、自動的に Scribble にプラグインされます。カスタム テキスト エディターで確認する重要なポイントUITextInputこれは、システムがテキスト コンテンツを取得し、範囲を選択し、認識されたテキストをビューに書き戻すためにこれを使用する必要があるためです。

ここには新しいアクセス コードはありません。開発者にとっての最初のステップは、記述するコードを減らすことです。可能であれば、標準のテキスト コントロールを使用します。ビューが標準のテキスト コントロールではない場合、または編集状態に入るために元々タップが必要な場合にのみ、後続のインタラクション API に入ります。

キーポイント:

  • UITextInputこれは、カスタム テキスト エディタが Scribble に接続するためのコア プロトコルです。 -UITextInteractionカスタム エディターがシステム標準のカーソルと選択 UI を取得できるようにします。
  • パスワード フィールドでは落書きはサポートされていないため、セッションではオートフィルの使用を明示的に推奨します。

使用UIScribbleInteraction書き込み中に UI を調整する

(09:15) インライン補完はキーボード入力で一般的であり、手書き時に手書きを妨げる可能性があります。セッションはテキストフィールドにメソッドを追加することで与えられますUIScribbleInteraction手書きが現在処理中かどうかを確認し、完了したテキストを非表示にします。

func updateSearchCompletion() {
    customSearchField.hideCompletionText = interaction.isHandlingWriting
}

キーポイント:

  • interaction.isHandlingWriting現在のインタラクションが Scribble 手書きを処理しているかどうかのみを説明します。
  • ここではテキスト入力ロジックに変更はありません。手書きを覆う視覚的な要素を避けるためです。
  • 該当するシナリオは、検索候補、インライン補完、プレースホルダー プロンプト、および書き込み領域に表示されるその他の UI です。

(09:35) ユーザーが Pencil を使用できることをインターフェイスが最初から判断できる場合、UIScribbleInteraction.isPencilInputExpected事前に入力エリア用のスペースを確保するために使用できます。

override func viewDidAppear(_ animated: Bool) {
    if UIScribbleInteraction.isPencilInputExpected {
        let lineHeight = textField.font?.lineHeight ?? 17.0
        let heightForScribble = lineHeight * 4.0
        heightConstraint.constant = heightForScribble
    }
}

キーポイント:

  • isPencilInputExpected現在の環境で鉛筆入力が可能かどうかを判断するために使用されるクラス属性です。
  • コードはフォント行の高さを使用して 4 行のテキストの高さを計算し、入力領域を手書きにより適したものにします。
  • Session は、書き込み中のレイアウトの移動を避けるために、ユーザーが書いていないときに UI の変更を行う必要があることを強調しています。

(09:51) もう 1 つのアプローチは、ユーザーが書き込みを終えた後にレイアウトを調整することです。エントリはデリゲートメソッドですscribbleInteractionDidFinishWriting

func scribbleInteractionDidFinishWriting(_ interaction: UIScribbleInteraction) {
    let lineHeight = textField.font?.lineHeight ?? 17.0
    let heightForScribble = lineHeight * 4.0
    heightConstraint.constant = heightForScribble
}

キーポイント:

  • scribbleInteractionDidFinishWritingScribble が書き込みを終了した後に呼び出されます。
  • 入力ボックスをより快適な高さに拡張したり、手書きによって一時的に影響を受けたレイアウトを復元したりするのに適しています。
  • このコードは前の例と同じ一連の高さ計算を使用します。違いはトリガー時間にあります。

描画モードでスクリブルをオフにする

(10:08) 一部のアプリでは、描画とテキスト編集の両方が可能です。ユーザーがキャンバスに書き込むとき、今度は線を引くかテキストを入力するかをシステムが自動的に判断することはできません。UIScribbleInteractionDelegateshouldBeginAt現在のモードでは落書きを拒否できます。

func scribbleInteraction(_ interaction: UIScribbleInteraction,
                         shouldBeginAt location: CGPoint) -> Bool {
    return !appIsInDrawingMode()
}

キーポイント:

  • location鉛筆が書き始める位置です。デリゲートは、現在の位置とアプリのステータスに基づいてそれを決定できます。
  • 戻るfalseScribble がこのビューで処理を開始できないようにします。
  • 描画、注釈、ホワイトボード アプリの場合、この判定により、ユーザーのストロークがテキスト入力と誤って入力されることを防ぐことができます。

使用UIIndirectScribbleInteraction非テキスト領域を書き込み可能にする

10:27UIIndirectScribbleInteraction別のタイプの問題に直面しています。通常、特定の領域はテキスト入力コントロールではありませんが、ユーザーは自然にそこに書き込みます。リマインダーの空白のリスト領域と、セッション例のノートの裏にある彫刻領域はすべてこのシナリオに当てはまります。

最初のステップは、ホスティング ビューにインタラクションをインストールすることです。

override init(frame: CGRect) {
    super.init(frame: frame)
    indirectScribbleInteraction = UIIndirectScribbleInteraction(delegate: self)
    addInteraction(indirectScribbleInteraction)
    ...
}

キーポイント:

  • UIIndirectScribbleInteractionビューにも追加されました。
  • デリゲートは、システムに書き込み可能領域を記述する責任があります。
  • 公式スニペットの省略記号は、サンプル ビューの他の初期化コードを表します。これは、Scribble アクセス ステップの一部ではありません。

(11:48) システムはまず、現在の四角形内にどのような書き込み可能な要素があるかを尋ねます。この例には彫刻領域が 1 つしかないため、識別子を直接返します。

func indirectScribbleInteraction(_ interaction: UIInteraction,
                                 requestElementsIn rect: CGRect,
                                 completion: @escaping ([ElementIdentifier]) -> Void) {
    completion(["EngravingIdentifier"])
}

キーポイント:

  • 要素識別子は、アプリ自体によって定義される安定した識別子です。
  • 複数の書き込み可能領域は複数の識別子を返すことができます。
  • 完了は非同期エントリです。複雑なビューでは、最初にヒット要素を計算してから返すことができます。

(12:14) 次に、ビュー内の要素の幾何学的位置をシステムに伝える必要があります。この例では、ユーザーがレタリング領域全体に書き込むことができるため、リターンbounds

func indirectScribbleInteraction(_ interaction: UIInteraction,
                                 frameForElement elementIdentifier: String) -> CGRect {
    return bounds
}

キーポイント:

  • frameForElementScribble が手書きを受け入れることができる領域を決定します。
  • 書き込み可能な領域がコントロールの一部のみをカバーするように、より小さい四角形を返すことができます。
  • フレームは、ユーザーから見える書き込み可能領域と一致している必要があります。一致していないと、鉛筆のヒットが信頼できないように見えます。

(12:28) ユーザーが実際に書き込むとき、システムはテキスト入力をサポートするレスポンダーを必要とします。この例では、必要に応じてテキスト フィールドを作成し、それをファーストレスポンダとして設定し、完了を通じてそれを返します。

func indirectScribbleInteraction(_ interaction: UIInteraction,
                                 focusElementIfNeeded elementIdentifier: String,
                                 referencePoint focusReferencePoint: CGPoint,
                                 completion: @escaping ((UIResponder & UITextInput)?) -> Void)
{
    if editingTextField == nil {
        createTextField()
    }
    editingTextField?.becomeFirstResponder()

    completion(editingTextField)
}

キーポイント:

  • 戻り値は両方でなければなりませんUIResponderそしてUITextInput、システムが認識されたテキストをそこに書き込むことができるようにします。 -createTextField()これは、ビュー階層に実際のテキスト フィールドをインストールするサンプル アプリの実装の詳細です。 -becomeFirstResponder()後続の入力をこのテキスト フィールドにルーティングします。

(12:57) 最後に、デリゲートは、この要素が現在フォーカスされているかどうかもシステムに伝えます。

func indirectScribbleInteraction(_ interaction: UIInteraction,
                                 isElementFocused elementIdentifier: String) -> Bool {
    // Indicate if our only element is currently installed and focused
    return editingTextField?.isFirstResponder ?? false
}

キーポイント:

  • このメソッドは、フォーカス プロセスを再度実行する必要があるかどうかをシステムに知らせます。
  • 例には要素が 1 つしかないため、チェックのみが行われますeditingTextField
  • 複数要素のシーンを押す必要がありますelementIdentifier別途判断してください。

重要ポイント

1. 鉛筆で使いやすい検索ボックス

対処方法: 検索ボックスに Scribble 適応のレイヤーを追加し、手書き時の入力完了プロンプトを非表示にし、必要に応じて入力領域を拡張します。

実行する価値がある理由: セッションの Spotlight の例は、インライン補完が手書きの妨げになることを示しています。メッセージの例は、入力ボックスが小さいと長い文章の作成が制限されることを示しています。

開始方法: 検索フィールドを追加するUIScribbleInteraction、使用isHandlingWritingテキスト補完を制御するには、次を使用します。isPencilInputExpectedまたはscribbleInteractionDidFinishWriting高さを調整します。

2. お絵かきアプリのテキスト注釈モード

対処方法: 同じキャンバス上での線描画とテキスト注釈をサポートし、描画モードでの落書きを無効にし、テキスト モードでの手書き入力を許可します。

これを行う価値がある理由: セッションでは、描画テキストと編集可能なテキストが混在している場合は、それを渡す必要があると明示的に述べています。shouldBeginAtScribble を開始するかどうかを決定します。

開始方法: キャンバス ビューに追加しますUIScribbleInteraction、デリゲート内の現在のツールのステータスを読み取り、描画ツールがアクティブ化されたときに戻ります。false

3. 空白領域にリスト項目を直接追加します。

機能: ユーザーがリストの下部の空白スペースに手書きして、新しいタスク、リマインダー、またはメモのエントリを自動的に作成できるようにします。

実行する価値がある理由: リマインダーの例は、この対話を示しています。空のスペースは元々テキスト コントロールではありませんが、ユーザーは自然にそこに新しいコンテンツを書き込みます。

開始方法: リストコンテナに追加UIIndirectScribbleInteraction、下の空白領域を要素として返します。focusElementIfNeeded新しいエントリのテキスト入力コントロールを作成してフォーカスします。

4. 製品カスタマイズにおける彫刻入力

手順: カップ、ノート、デバイス ケースなど、製品プレビュー上の指定された領域に彫刻内容を手書きします。

実行する価値がある理由: セッション彫刻の例は、非編集領域から非表示のテキスト フィールドへの完全なリンクを示しています。

開始方法: を使用しますrequestElementsIn彫刻領域を公開するには、次を使用します。frameForElement書き込み可能な範囲を返し、実際のテキストフィールドを次のように使用します。UIResponder & UITextInputシステムに戻ります。

5. 特殊QAリストの鉛筆入力

手順: iPad アプリに鉛筆入力テストのセットを追加します: 標準のテキスト コントロール、検索ボックス、フォーム、空白のリスト領域、カスタム エディター。

実行する価値がある理由: 標準コントロールでは落書きがデフォルトで利用可能ですが、セッションでは開発者に最初にタップする必要があること、レイアウトが移動すること、スペースが狭すぎること、およびカスタマイズを確認するよう通知します。UITextInput未完成なシーン。

開始方法: まず Apple Pencil を使用してすべてのテキストエントリをクリアし、次に異常なエントリに個別にパッチを適用します。UITextInputUIScribbleInteractionまたはUIIndirectScribbleInteraction

関連セッション

  • PencilKit の新機能 - PencilKit は iPad アプリで描画、書き込み、アニメーションを処理し、PKToolPicker、PKCanvasView、PKStroke などのアップデートを導入します。
  • PencilKit 図面の検査、変更、構築 - 詳細な PKDrawing、PKStroke、インク、パス、ポイント。鉛筆入力後の認識と編集に適しています。
  • アプリでハードウェア キーボードをサポートする — iPadOS および Mac Catalyst アプリのハードウェア キーボード ナビゲーション、ショートカット キー、レスポンダー チェーン、生のキーボード イベントについて説明します。
  • iPadOS ポインター用のビルド — ポインター インタラクション API を使用して、iPad ポインターのボタン、カスタム ビュー、およびエリア アニメーションをカスタマイズします。
  • Build for iPad — Pencil 入力スペースの設計の基礎となる、iPad アプリの複数列レイアウト、リスト、中断の少ないナビゲーションについて説明します。

コメント

GitHub Issues · utterances