Benutzerdefinierte Texteditoren

Benutzerdefinierte Texteditoren sind Ansichten, die keine EditText-Komponenten oder WebView-Textwidgets sind, aber Texteingabe unterstützen. Dazu implementieren Sie den onCreateInputConnection()-Callback, der aufgerufen wird, wenn eine Ansicht hervorgehoben wird und das System ein InputConnection für die Ansicht anfordert.

Bei einem Aufruf von onCheckIsTextEditor() von einem benutzerdefinierten Texteditor sollte true zurückgegeben werden.

In benutzerdefinierten Texteditoren wird das Schreiben mit Eingabestift unterstützt

Android 14 (API-Level 34) und höher unterstützen standardmäßig die Eingabe eines Eingabestifts in standardmäßigen Android-Texteingabekomponenten (siehe Eingabestift in Textfeldern). Benutzerdefinierte Texteingabefelder (oder Editoren) erfordern jedoch eine zusätzliche Entwicklung.

So erstellen Sie einen benutzerdefinierten Texteditor:

  1. Initiierung per Handschrift aktivieren
  2. Unterstützung für handschriftliche Eingaben
  3. Handschriftgesten unterstützen (Auswählen, Löschen, Einfügen usw.)
  4. Cursorposition und andere Positionsdaten für den IME bereitstellen
  5. Symbol für die Handschrifteingabe mit Eingabestift anzeigen

Initiierung per Handschrift aktivieren

Besteht eine Ansicht nur aus einem einzigen Texteditor, kann das Ansichtssystem automatisch die Eingabe des Eingabestifts für die Ansicht initiieren. Andernfalls muss in der Ansicht eine eigene Logik zur Initiierung der Handschrift implementiert werden.

Automatische Aktivierung der Handschrift

Wenn in einer Ansicht ein einzelner Texteditor und kein anderer Inhalt angezeigt wird, kann in der Ansicht die automatische Handschriftinitiierung des Ansichtssystems durch Aufrufen von setAutoHandwritingEnabled(true) aktiviert werden.

Wenn die automatische Handschrift aktiviert ist und die Eingabe des Eingabestifts an einer beliebigen Stelle innerhalb der Handschriftgrenzen der Ansicht beginnt, wird automatisch der Handschriftmodus gestartet. Der Editor für Eingabemethoden (IME) empfängt die Bewegungsereignisse des Eingabestifts und führt den erkannten Text aus.

Eingabefeld mit umgebendem Rechteck, das die Grenzen für die Erkennung von Eingabestiftbewegungen angibt.
Abbildung 1: Handschrift innerhalb der Grenzen eines EditText-Felds.

Benutzerdefinierte Handschrifterstellung

Wenn eine Ansicht neben einem Texteditor mehrere Texteditoren oder Inhalte enthält, muss in der Ansicht eine eigene Logik zum Initiieren der Handschrift implementiert werden:

  1. Deaktivieren Sie die automatische Auslösung der Handschrift durch das Ansichtssystem, indem Sie setAutoHandwritingEnabled(false) aufrufen.

  2. Behalten Sie den Überblick über alle Texteditoren, die in der Ansicht sichtbar sind.

  3. Mit der Ansicht in dispatchTouchEvent() empfangene Bewegungsereignisse werden überwacht.

    • Wenn die Bewegung des Eingabestifts innerhalb der Handschriftgrenzen eines Texteditors erfolgt, fokussieren Sie den Texteditor (falls nicht bereits fokussiert).

    • Wenn der Editor noch nicht im Fokus war, starten Sie den IME des Editors mit neuen Inhalten neu. Rufen Sie dazu InputMethodManager#restartInput() auf.

    • Starten Sie die Eingabestift-Handschrift, indem Sie InputMethodManager#startStylusHandwriting() aufrufen.

Wenn sich ein Texteditor innerhalb einer scrollbaren Ansicht befindet, sollte die Bewegung des Eingabestifts innerhalb der Handschriftgrenzen des Editors als Handschrift und nicht als Scrollen angesehen werden. Mit ViewParent#requestDisallowInterceptTouchEvent() verhindern Sie, dass eine scrollbare Ancestor-Ansicht Touchereignisse von einem Texteditor abfängt.

API-Details

  • MotionEvent#getToolType(): Gibt an, ob der MotionEvent von einem Eingabestift stammt. In diesem Fall ist der Rückgabewert TOOL_TYPE_STYLUS oder TOOL_TYPE_ERASER.

  • InputMethodManager#isStylusHandwritingAvailable(): Gibt an, ob der IME die Handschrift mit Eingabestiften unterstützt. Rufen Sie diese Methode vor jedem Aufruf von InputMethodManager#startStylusHandwriting() auf, da sich die Verfügbarkeit der Handschrift möglicherweise geändert hat.

  • InputMethodManager#startStylusHandwriting(): Der IME wechselt in den Handschriftmodus. Ein ACTION_CANCEL-Bewegungsereignis wird an die App gesendet, um die aktuelle Geste abzubrechen. Bewegungsereignisse für Eingabestifte werden nicht mehr an die App gesendet.

    Bewegungsereignisse des Eingabestifts der aktuellen Geste, die bereits an die App gesendet wurden, werden an den IME weitergeleitet. Der IME ist erforderlich, um ein Eingabestiftfenster anzuzeigen, über das der IME alle folgenden MotionEvent-Objekte empfängt. Der IME führt mithilfe der InputConnection APIs erkannten handschriftlichen Text aus.

    Wenn der IME nicht in den Handschriftmodus wechseln kann, ist dieser Methodenaufruf kein Vorgang.

Unterstützung für handschriftliche Eingaben

Wenn Sie das Argument EditorInfo von View#onCreateInputConnection(EditorInfo) eingeben, rufen Sie setStylusHandwritingEnabled() auf, um den IME darüber zu informieren, dass der Texteditor Handschrift unterstützt. Deklarieren Sie unterstützte Touch-Gesten mit setSupportedHandwritingGestures() und setSupportedHandwritingGesturePreviews().

Handschriftgesten unterstützen

IMEs können verschiedene handschriftliche Touch-Gesten unterstützen, z. B. umkreisenden Text zum Auswählen oder Kritzeln über Text, um ihn zu löschen.

Abbildung 2: Kreis, um Text auszuwählen.
Abbildung 3: Skizze, um Text zu löschen.

Benutzerdefinierte Editoren implementieren InputConnection#performHandwritingGesture() und InputConnection#previewHandwritingGesture(), um verschiedene HandwritingGesture-Typen wie SelectGesture, DeleteGesture und InsertGesture zu unterstützen.

Deklarieren Sie unterstützte Handschriftgesten, wenn Sie das Argument EditorInfo von View#onCreateInputConnection(EditorInfo) ausfüllen. Weitere Informationen finden Sie im Abschnitt Unterstützung für Handschrift deklarieren.

API-Details

  • InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer): Implementiert Touch-Gesten. Das Argument HandwritingGesture enthält Standortinformationen, mit denen Sie bestimmen können, an welcher Stelle im Text die Geste ausgeführt werden soll. Beispielsweise stellt SelectGesture ein RectF-Objekt bereit, das den ausgewählten Textbereich angibt, und InsertGesture stellt ein PointF-Objekt bereit, das den Textversatz angibt, bei dem Text eingefügt werden soll.

    Verwenden Sie die Parameter Executor und IntConsumer, um das Ergebnis des Vorgangs zurückzusenden. Wenn sowohl das Executor- als auch das Consumer-Argument angegeben ist, verwenden Sie den Executor, um IntConsumer#accept() aufzurufen. Beispiel:

    
    executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
    
    
  • HandwritingGesture#getFallbackText(): Stellt einen Fallback-Text bereit, den der IME an der Cursorposition ausführt, wenn sich unter dem Bereich einer Handschriftgeste kein entsprechender Text befindet.

    Manchmal kann der IME nicht ermitteln, ob mit einer Eingabestiftgeste eine Geste ausgeführt oder Text per Hand geschrieben werden soll. Ein benutzerdefinierter Texteditor bestimmt die Absicht des Nutzers und führt (je nach Kontext) die entsprechende Aktion an der Bewegungsposition aus.

    Wenn der IME beispielsweise nicht ermitteln kann, ob der Nutzer einen nach unten weisenden Caret ⋁ zeichnen soll, um eine Geste zum Einfügen des Leerzeichens auszuführen oder den Buchstaben „v“ von Hand zu schreiben, kann der IME ein InsertGesture mit dem Fallback-Text „v“ senden.

    Der Editor sollte zuerst versuchen, die Touch-Geste „Leerzeichen einfügen“ auszuführen. Wenn die Touch-Geste nicht ausgeführt werden kann, weil z. B. an der angegebenen Position kein Text vorhanden ist, sollte der Editor „v“ an der Cursorposition einfügen.

  • InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) – Zeigt eine Vorschau einer laufenden Touch-Geste an. Wenn der Nutzer beispielsweise beginnt, einen Kreis um Text zu ziehen, kann eine Live-Vorschau der resultierenden Auswahl angezeigt und kontinuierlich aktualisiert werden, während der Nutzer mit dem Zeichnen fortfährt. Eine Vorschau ist nur für bestimmte Gestentypen verfügbar (siehe PreviewableHandwritingGesture).

    Der Parameter CancellationSignal kann vom IME verwendet werden, um die Vorschau abzubrechen. Wird die Vorschau durch andere Ereignisse unterbrochen, z. B. wenn der Text programmatisch geändert oder neue InputConnection-Befehle ausgeführt werden, kann der benutzerdefinierte Editor die Vorschau abbrechen.

    Vorschaugesten dienen nur der Anzeige und sollten den Status des Editors nicht ändern. Bei der Vorschau für SelectGesture wird beispielsweise der aktuelle Auswahlbereich des Editors ausgeblendet und der Bereich für die Gestenvorschau hervorgehoben. Sobald die Vorschau abgebrochen wird, sollte der Editor den vorherigen Auswahlbereich wiederherstellen.

Cursorposition und andere Positionsdaten angeben

Im Handschriftmodus kann der IME die Cursorposition und andere Positionsdaten mit InputConnection#requestCursorUpdates() anfordern. Der benutzerdefinierte Editor antwortet mit einem Aufruf von InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo). Die für das Schreiben mit Eingabestiften relevanten Daten in CursorAnchorInfo werden über die folgenden CursorAnchorInfo.Builder-Methoden bereitgestellt:

  • setInsertionMarkerLocation(): Legt die Position des Cursors fest. Der IME verwendet den Wert, um handschriftliche Tinte an der Cursorposition zu animieren.
  • setEditorBoundsInfo(): Legt die Grenzen des Bearbeiters und die Handschrift fest. Anhand dieser Daten positioniert der IME seine Handschriftsymbolleiste auf dem Bildschirm.
  • addVisibleLineBounds(): Legt die Grenzen aller sichtbaren (oder teilweise sichtbaren) Textzeilen im Editor fest. Der IME verwendet die Liniengrenzen, um die Genauigkeit der Erkennung von Handschriftgesten zu verbessern.
  • setTextAppearanceInfo(): Legt die Textdarstellung mit Informationen fest, die aus dem Texteingabefeld abgeleitet wurden. Der IME verwendet die Informationen, um die handschriftliche Tinte zu gestalten.

Symbol für die Handschrifteingabe mit Eingabestift anzeigen

Das Symbol für die Handschrift des Eingabestifts wird eingeblendet, wenn der Eingabestift den Mauszeiger über die Handschriftgrenze Ihres benutzerdefinierten Texteditors bewegt und der ausgewählte IME die Handschrift mit Eingabestift unterstützt (InputMethodManager#isStylusHandwritingAvailable()).

Überschreiben Sie View#onResolvePointerIcon(), um ein Hover-Symbol für Handschrift mit Eingabestift zu sehen. Rufen Sie in der Überschreibung PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING) auf, um auf das Systemsymbol für die Eingabe des Eingabestifts zuzugreifen, der mit dem Mauszeiger bewegt wird.

Weitere Informationen