Niestandardowe edytory tekstu

Niestandardowe edytory tekstu to widoki, które nie są komponentami EditText ani widżetami tekstu WebView, ale obsługują wprowadzanie tekstu przez zaimplementowanie wywołania zwrotnego onCreateInputConnection(), które jest wywoływane, gdy widok jest aktywny, a system wysyła żądanie jego wyświetlenia InputConnection.

Wywołanie metody onCheckIsTextEditor() z niestandardowego edytora tekstu powinno zwracać wartość true.

Obsługa pisma odręcznego rysikiem w niestandardowych edytorach tekstu

Android 14 (poziom interfejsu API 34) i nowsze domyślnie obsługują wprowadzanie tekstu przy użyciu rysika w standardowych komponentach do wprowadzania tekstu na Androidzie (zobacz Wprowadzanie rysika w polach tekstowych). Jednak niestandardowe pola do wprowadzania tekstu (lub edytora) wymagają dodatkowych modyfikacji.

Aby utworzyć niestandardowy edytor tekstu:

  1. Włącz inicjowanie pisma odręcznego
  2. Zadeklaruj obsługę pisma odręcznego
  3. Obsługa gestów pisma odręcznego (zaznaczanie, usuwanie, wstawianie itp.)
  4. Podaj lokalizację kursora i inne dane o pozycji do IME
  5. Wyświetlaj ikonę pisma odręcznego rysikiem po najechaniu kursorem

Włącz inicjowanie pisma odręcznego

Jeśli widok obejmuje tylko 1 edytor tekstu, system widoku może automatycznie inicjować w widoku pismo odręczne rysikiem. W przeciwnym razie widok musi implementować własną logikę inicjowania pisma odręcznego.

Automatyczne inicjowanie pisma odręcznego

Jeśli w widoku danych jest tylko 1 edytor tekstu, a nie ma żadnych innych treści, w widoku można włączyć automatyczne inicjowanie pisma odręcznego w systemie widoku, wywołując metodę setAutoHandwritingEnabled(true).

Po włączeniu automatycznego pisma odręcznego ruch rysika rozpoczyna się w dowolnym miejscu w obszarze pisma odręcznego, automatycznie uruchamia tryb pisma odręcznego. Edytor metody wprowadzania (IME) odbiera zdarzenia ruchu rysika i zatwierdza rozpoznany tekst.

Pole do wprowadzania danych otoczone prostokątem, które wskazuje granice wykrywania zdarzeń ruchu rysika.
Rysunek 1. Pismo odręczne w granicach pola EditText.

Inicjowanie niestandardowego pisma odręcznego

Jeśli widok zawiera nie tylko 1 edytor tekstu, ale też wiele innych edytorów tekstu, musi on implementować własną logikę inicjowania pisma odręcznego w ten sposób:

  1. Aby zrezygnować z automatycznego inicjowania pisma odręcznego w systemie wyświetlania, zadzwoń pod numer setAutoHandwritingEnabled(false).

  2. Śledź wszystkie edytory tekstu widoczne w widoku.

  3. Monitoruj zdarzenia ruchu otrzymane przez widok w dispatchTouchEvent().

    • Gdy rysik zacznie się przesuwać w granicę pisma odręcznego w edytorze tekstu, zaznacz edytor tekstu (jeśli jeszcze nie jest zaznaczony).

    • Jeśli edytor nie jest jeszcze zaznaczony, uruchom go ponownie i dodaj nową treść, wywołując metodę InputMethodManager#restartInput().

    • Rozpocznij sesję pisma odręcznego rysikiem, wywołując metodę InputMethodManager#startStylusHandwriting().

Jeśli edytor tekstu znajduje się w widoku z możliwością przewijania, ruch rysika w granicach pisma odręcznego edytującego należy traktować jako pismo odręczne, a nie przewijanie. Użyj metody ViewParent#requestDisallowInterceptTouchEvent(), aby uniemożliwić przewijany widok elementu nadrzędnego przed przechwytywaniem zdarzeń dotknięcia z edytora tekstu.

Szczegóły interfejsu API

  • MotionEvent#getToolType() – wskazuje, czy element MotionEvent pochodzi z rysika. W takim przypadku zwracana wartość to TOOL_TYPE_STYLUS czy TOOL_TYPE_ERASER.

  • InputMethodManager#isStylusHandwritingAvailable() – wskazuje, czy edytor IME obsługuje pismo odręczne rysikiem. Wywołuj tę metodę przed każdym wywołaniem funkcji InputMethodManager#startStylusHandwriting(), ponieważ dostępność pisma odręcznego mogła się zmienić.

  • InputMethodManager#startStylusHandwriting() – powoduje, że edytor IME przechodzi w tryb pisma odręcznego. Zdarzenie ruchu ACTION_CANCEL jest wysyłane do aplikacji, aby anulować bieżący gest. Zdarzenia ruchu rysikiem nie są już wysyłane do aplikacji.

    Zdarzenia ruchu rysika w ramach bieżącego gestu, które zostały już wysłane do aplikacji, są przekazywane do IME. IME jest wymagany, aby pokazać okno atramentu rysikiem, przez które otrzymuje on wszystkie kolejne obiekty MotionEvent. IME zatwierdza rozpoznany tekst pismem odręcznym za pomocą interfejsów API InputConnection.

    Jeśli edytor IME nie może włączyć trybu pisma odręcznego, nie można wywołać tej metody.

Zadeklaruj obsługę pisma odręcznego

Podczas wypełniania argumentu EditorInfo View#onCreateInputConnection(EditorInfo) wywołaj setStylusHandwritingEnabled(), aby poinformować IME, że edytor tekstu obsługuje pismo odręczne. Zadeklaruj obsługiwane gesty za pomocą elementów setSupportedHandwritingGestures() i setSupportedHandwritingGesturePreviews().

Obsługa gestów pisma odręcznego

IME obsługują różne gesty pisma odręcznego, np. zaznaczanie tekstu wokół jego zaznaczenia lub rysowanie po tekście, aby go usunąć.

Rysunek 2. Zakreśl, aby zaznaczyć tekst.
Rysunek 3. Zamaż, aby usunąć tekst.

Edytory niestandardowe implementują InputConnection#performHandwritingGesture() i InputConnection#previewHandwritingGesture() do obsługi różnych typów HandwritingGesture, na przykład SelectGesture, DeleteGesture i InsertGesture.

Zadeklaruj obsługiwane gesty pisma odręcznego podczas wypełniania argumentu EditorInfo w polu View#onCreateInputConnection(EditorInfo) (zobacz sekcję Deklaruj obsługę pisma odręcznego).

Szczegóły interfejsu API

  • InputConnection#performHandwritingGesture(HandwritingGesture, Executor, IntConsumer) – implementuje gesty. Argument HandwritingGesture zawiera informacje o lokalizacji, które pozwalają określić, w którym miejscu tekstu należy wykonać gest. Na przykład SelectGesture udostępnia obiekt RectF, który określa wybrany zakres tekstu, a InsertGesture obiekt PointF określający przesunięcie tekstu, przy którym ma zostać wstawiony tekst.

    Użyj parametrów Executor i IntConsumer, aby odesłać wynik operacji. Jeśli podasz zarówno argumenty wykonawcy, jak i klienta, użyj polecenia wykonawcy do wywołania IntConsumer#accept(), na przykład:

    
    executor.execute { consumer.accept(HANDWRITING_GESTURE_RESULT_SUCCESS) }
    
    
  • HandwritingGesture#getFallbackText() – wyświetla tekst zastępczy zatwierdzone przez edytor IME w położeniu kursora, jeśli pod obszarem pisma odręcznego nie ma żadnego tekstu.

    Czasami edytor IME nie jest w stanie określić, czy gest rysika ma służyć do wykonywania operacji gestu czy do pisania odręcznego tekstu. Za określenie zamiaru użytkownika i wykonanie odpowiedniego działania (w zależności od kontekstu) w miejscu gestu odpowiada edytor niestandardowego tekstu.

    Jeśli na przykład edytor IME nie może określić, czy użytkownik miał narysować kursor w dół ⋁, aby wykonać gest wstawiania spacji lub odręcznie napisać literę „v”, edytor IME może wysłać InsertGesture z tekstem zastępczym „v”.

    Edytor powinien najpierw spróbować wykonać gest wstawiania spacji. Jeśli nie można wykonać gestu (na przykład w określonej lokalizacji nie ma tekstu), edytor powinien zamiast tego wstawić „v” w miejscu kursora.

  • InputConnection#previewHandwritingGesture(PreviewableHandwritingGesture, CancellationSignal) – wyświetla podgląd trwającego gestu. Gdy na przykład użytkownik zacznie rysować okrąg wokół jakiegoś tekstu, podgląd na żywo wyniku wyboru może być na bieżąco aktualizowany w miarę kontynuacji rysowania. Można wyświetlać podgląd tylko niektórych typów gestów (patrz PreviewableHandwritingGesture).

    Edytor IME może używać parametru CancellationSignal do anulowania podglądu. Jeśli podgląd zostanie zakłócony przez inne zdarzenia (np. zmiana zostanie automatycznie zmieniona lub pojawi się nowe polecenie InputConnection), edytor niestandardowy może anulować podgląd.

    Gesty podglądu są tylko do wyświetlania i nie powinny zmieniać stanu edytora. Na przykład podgląd SelectGesture ukrywa bieżący zakres wyboru edytora i wyróżnia zakres podglądu gestów. Gdy jednak podgląd zostanie anulowany, edytor powinien przywrócić poprzedni zakres wyboru.

Podaj lokalizację kursora i inne dane o pozycji

W trybie pisma odręcznego edytor IME może zażądać lokalizacji kursora i innych danych o pozycji, używając InputConnection#requestCursorUpdates(). Edytor niestandardowy odpowiada za pomocą wywołania InputMethodManager#updateCursorAnchorInfo(View, CursorAnchorInfo). Dane w CursorAnchorInfo dotyczące pisma odręcznego rysikiem są dostarczane za pomocą tych metod CursorAnchorInfo.Builder:

  • setInsertionMarkerLocation() – ustawia lokalizację kursora. Edytor IME używa jej do animowania atramentu w położeniu kursora.
  • setEditorBoundsInfo() – wyznacza granice edytora i pismo odręczne. Edytor IME używa tych danych do umieszczenia paska narzędzi pisma odręcznego na ekranie.
  • addVisibleLineBounds()– wyznacza granice wszystkich widocznych (lub częściowo widocznych) wierszy tekstu w edytorze. IME używa granic linii, aby zwiększyć dokładność rozpoznawania gestów pisma odręcznego.
  • setTextAppearanceInfo() – ustawia wygląd tekstu na podstawie informacji uzyskanych z pola do wprowadzania tekstu. IME używa tych informacji do określania stylu pisma odręcznego.

Wyświetlaj ikonę pisma odręcznego rysikiem po najechaniu kursorem

Wyświetlaj ikonę pisma odręcznego rysika, gdy rysik najedzie na granice pisma odręcznego w niestandardowym edytorze tekstu, a wybrany edytor obsługuje pismo odręczne styl (InputMethodManager#isStylusHandwritingAvailable()).

Zastąp View#onResolvePointerIcon(), aby uzyskać ikonę najeżdżania kursorem na pismo odręczne rysikiem. W zastępowaniu wywołaj PointerIcon.getSystemIcon(context, PointerIcon.TYPE_HANDWRITING), aby uzyskać dostęp do ikony systemu po najechaniu kursorem na pismo odręczne rysika.

Dodatkowe materiały