Utwórz metodę wprowadzania

Edytor metody wprowadzania (IME) to element sterujący, który umożliwia użytkownikom wpisywanie tekstu. Android zapewnia rozbudowaną platformę metod wprowadzania, która pozwala aplikacjom udostępniać użytkownikom alternatywne metody wprowadzania, takie jak klawiatura ekranowa czy rozpoznawanie mowy. Po zainstalowaniu IME użytkownik może je wybrać w ustawieniach systemu i używać go w całym systemie. Można włączyć tylko jeden edytor IME naraz.

Aby dodać edytor IME do systemu Android, utwórz aplikację na Androida zawierającą klasę o rozszerzeniu InputMethodService. Zwykle tworzysz też działanie „ustawień”, które przekazuje opcje do usługi IME. Możesz też zdefiniować interfejs ustawień, który będzie wyświetlany w ramach ustawień systemowych.

Na tej stronie znajdują się następujące tematy:

Jeśli nie znasz jeszcze IME, przeczytaj najpierw artykuł wprowadzający Wyświetlanie ekranowych metod wprowadzania.

Cykl życia IME

Ten schemat opisuje cykl życia IME:

Obraz przedstawiający cykl życia IME.
Rysunek 1. Cykl życia IME.

W kolejnych sekcjach opisano, jak wdrożyć interfejs użytkownika i kod powiązany z edytorem IME zgodnym z tym cyklem życia.

Zadeklaruj komponenty IME w pliku manifestu

IME w systemie Android to aplikacja na Androida zawierająca specjalną usługę IME. Plik manifestu aplikacji musi zadeklarować usługę, zażądać niezbędnych uprawnień, podać filtr intencji pasujący do działania action.view.InputMethod oraz podać metadane określające właściwości IME. Dodatkowo, aby udostępnić interfejs ustawień, który pozwala użytkownikowi modyfikować działanie IME, możesz zdefiniować działanie „ustawień”, które będzie można uruchamiać w Ustawieniach systemu.

Ten fragment deklaruje usługę IME. Prosi o pozwolenie BIND_INPUT_METHOD na połączenie IME z systemem, skonfigurowanie filtra intencji pasującego do działania android.view.InputMethod oraz zdefiniowanie metadanych IME:

<!-- Declares the input method service. -->
<service android:name="FastInputIME"
    android:label="@string/fast_input_label"
    android:permission="android.permission.BIND_INPUT_METHOD">
    <intent-filter>
        <action android:name="android.view.InputMethod" />
    </intent-filter>
    <meta-data android:name="android.view.im"
               android:resource="@xml/method" />
</service>

Następny fragment zawiera deklarację ustawień IME. Zawiera on filtr intencji dla ACTION_MAIN, który wskazuje, że to działanie jest głównym punktem wejścia aplikacji IME:

<!-- Optional: an activity for controlling the IME settings. -->
<activity android:name="FastInputIMESettings"
    android:label="@string/fast_input_settings">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>

Możesz też zapewnić dostęp do ustawień IME bezpośrednio z jego interfejsu.

Interfejs API metody wprowadzania

Klasy właściwe dla IME znajdują się w pakietach android.inputmethodservice i android.view.inputmethod. Klasa KeyEvent jest ważna przy obsłudze znaków klawiatury.

Centralną częścią IME jest komponent usługi – klasa rozszerzająca InputMethodService. Oprócz implementowania normalnego cyklu życia usługi ta klasa zawiera wywołania zwrotne umożliwiające udostępnianie interfejsu edytora IME, obsługę danych wejściowych użytkownika i dostarczanie tekstu do najważniejszego pola. Domyślnie klasa InputMethodService zapewnia większość implementacji do zarządzania stanem i widocznością edytora IME oraz do komunikacji z bieżącym polem do wprowadzania danych.

Ważne są też te zajęcia:

BaseInputConnection
Określa kanał komunikacji od InputMethod z powrotem do aplikacji, która odbiera dane wejściowe. Umożliwia czytanie tekstu wokół kursora, zatwierdzanie tekstu w polu tekstowym i wysyłanie nieprzetworzonych kluczowych zdarzeń do aplikacji. Aplikacje muszą rozszerzać tę klasę, a nie implementować podstawowego interfejsu InputConnection.
KeyboardView
Rozszerzenie View, które renderuje klawiaturę i reaguje na zdarzenia wejściowe użytkownika. Układ klawiatury jest określany przez instancję Keyboard, którą można zdefiniować w pliku XML.

Projektowanie interfejsu metody wprowadzania

IME ma 2 główne elementy wizualne: widok wejściowy i widok kandydatów. Musisz zaimplementować tylko te elementy, które są istotne dla projektowanej metody wprowadzania.

Widok wejściowy

Widok do wprowadzania danych to interfejs, w którym użytkownik wpisuje tekst w postaci kliknięć klawiszy, pisma odręcznego lub gestów. Przy pierwszym wyświetleniu IME system wywołuje wywołanie zwrotne onCreateInputView(). W swojej implementacji tej metody utwórz układ, który ma być wyświetlany w oknie IME, i przywróć układ do systemu. Ten fragment kodu pokazuje przykład implementacji metody onCreateInputView():

Kotlin

override fun onCreateInputView(): View {
    return layoutInflater.inflate(R.layout.input, null).apply {
        if (this is MyKeyboardView) {
            setOnKeyboardActionListener(this@MyInputMethod)
            keyboard = latinKeyboard
        }
    }
}

Java

@Override
public View onCreateInputView() {
    MyKeyboardView inputView =
        (MyKeyboardView) getLayoutInflater().inflate(R.layout.input, null);

    inputView.setOnKeyboardActionListener(this);
    inputView.setKeyboard(latinKeyboard);

    return inputView;
}

W tym przykładzie MyKeyboardView jest wystąpieniem niestandardowej implementacji KeyboardView, która renderuje element Keyboard.

Widok kandydatów

Widok kandydatów to interfejs użytkownika, w którym edytor IME wyświetla potencjalne poprawki słów lub sugestie, które użytkownik może wybrać. W cyklu życia IME system wywołuje onCreateCandidatesView(), gdy jest gotowy do wyświetlenia widoku kandydatów. W swojej implementacji tej metody zwracaj układ, który wyświetla sugestie słów, lub zwracaj wartość null, jeśli nie chcesz niczego wyświetlać. Odpowiedź o wartości null to działanie domyślne, więc nie musisz go stosować, jeśli nie podajesz sugestii.

Uwagi na temat projektu UI

W tej sekcji opisujemy wybrane kwestie związane z projektowaniem interfejsu IME.

Obsługa różnych rozmiarów ekranu

Interfejs edytora IME musi być w stanie skalować się do różnych rozmiarów ekranu i obsługiwać zarówno orientację poziomą, jak i pionową. W trybie niepełnoekranowym pozostaw wystarczającą ilość miejsca w aplikacji, aby wyświetlić pole tekstowe i wszelki powiązany kontekst, tak aby edytor zajmował nie więcej niż połowę ekranu. W trybie pełnoekranowym IME nie jest to problemem.

Obsługa różnych typów danych wejściowych

Pola tekstowe w Androidzie umożliwiają ustawienie określonego typu danych wejściowych, np. dowolnego tekstu, liczb, adresów URL, adresów e-mail i ciągów wyszukiwania. Podczas wdrażania nowego edytora IME wykrywaj typ danych wejściowych każdego pola i zapewnij mu odpowiedni interfejs. Nie musisz jednak konfigurować edytora IME, aby sprawdzać, czy użytkownik wpisuje prawidłowy tekst dla danego typu danych wejściowych. Za to odpowiada aplikacja, do której należy pole tekstowe.

Oto na przykład interfejs edytora łacińskiego IME do wprowadzania tekstu na platformie Androida:

Obraz przedstawiający wprowadzanie tekstu w edytorze IME dla alfabetu łacińskiego
Rysunek 2. Wprowadzanie tekstu łacińskiego IME.

A oto interfejs, który zawiera łaciński edytor do wprowadzania danych liczbowych platformy Androida:

Obraz przedstawiający wprowadzanie liczbowe w edytorze IME alfabetu łacińskiego
Rysunek 3. Wprowadzanie numeryczne w edytorze łacińskim IME.

Gdy pole do wprowadzania danych zostanie zaznaczone i uruchomi się edytor IME, system wywoła onStartInputView(), przekazując obiekt EditorInfo zawierający szczegóły typu danych wejściowych i innych atrybutów pola tekstowego. W tym obiekcie pole inputType zawiera typ danych wejściowych pola tekstowego.

Pole inputType to pole int, które zawiera wzorce bitów dla różnych ustawień typów danych wejściowych. Aby przetestować je pod kątem typu wprowadzania w polu tekstowym, zamaskowanie go stałą TYPE_MASK_CLASS w ten sposób:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

Wzorzec bitów typu danych wejściowych może mieć jedną z kilku wartości, na przykład:

TYPE_CLASS_NUMBER
Pole tekstowe do wpisywania cyfr. Jak pokazano na ilustracji 3, edytor łaciński jest w przypadku pól tego typu z klawiaturą liczbową.
TYPE_CLASS_DATETIME
Pole tekstowe do wpisania daty i godziny.
TYPE_CLASS_PHONE
Pole tekstowe do wpisywania numerów telefonów.
TYPE_CLASS_TEXT
Pole tekstowe do wpisywania obsługiwanych znaków.

Te stałe opisano bardziej szczegółowo w dokumentacji referencyjnej InputType.

Pole inputType może zawierać inne bity wskazujące wariant typu pola tekstowego, na przykład:

TYPE_TEXT_VARIATION_PASSWORD
Wariant TYPE_CLASS_TEXT do wpisywania haseł. Metoda wprowadzania wyświetla dingbaty zamiast rzeczywistego tekstu.
TYPE_TEXT_VARIATION_URI
Wariant TYPE_CLASS_TEXT służący do wpisywania adresów URL i innych identyfikatorów URI.
TYPE_TEXT_FLAG_AUTO_COMPLETE
Wariant TYPE_CLASS_TEXT do wpisywania tekstu automatycznie uzupełnianego przez aplikację ze słownika, wyszukiwarki lub innej usługi.

Podczas testowania tych wariantów ustaw maskę inputType odpowiednią stałą wartością. Dostępne stałe maski są wymienione w dokumentacji referencyjnej InputType.

Wyślij tekst do aplikacji

Gdy użytkownik wprowadza tekst w Twoim edytorze IME, możesz wysłać tekst do aplikacji, wysyłając poszczególne kluczowe zdarzenia lub edytując tekst wokół kursora w polu tekstowym aplikacji. W obu przypadkach, aby wyświetlić tekst, użyj wystąpienia InputConnection. Aby pobrać tę instancję, wywołaj InputMethodService.getCurrentInputConnection().

Edytowanie tekstu wokół kursora

Gdy edytujesz istniejący tekst, możesz użyć tych przydatnych metod w BaseInputConnection:

getTextBeforeCursor()
Zwraca wartość CharSequence zawierającą liczbę żądanych znaków przed bieżącą pozycją kursora.
getTextAfterCursor()
Zwraca wartość CharSequence zawierającą liczbę żądanych znaków po bieżącej pozycji kursora.
deleteSurroundingText()
Usuwa określoną liczbę znaków przed bieżącą pozycją kursora i po niej.
commitText()
Kompletuje komponent CharSequence w polu tekstowym i ustawia nową pozycję kursora.

Na przykład ten fragment pokazuje, jak zastąpić 4 znaki po lewej stronie kursora tekstem „Hello!”:

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.deleteSurroundingText(4, 0)
    ic.commitText("Hello", 1)
    ic.commitText("!", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);

Obsługa tworzenia tekstu przed zatwierdzeniem

Jeśli edytor IME przewiduje tekst lub wymaga wykonania wielu czynności w celu utworzenia glifu bądź słowa, możesz wyświetlać postęp w polu tekstowym do czasu, aż użytkownik wpisze słowo. Następnie możesz zastąpić kompozycję wykonaną uzupełnionym tekstem. Możesz nadać tekstowi wyjątkowego charakteru, dodając do niego span podczas przekazywania go do setComposingText().

Ten fragment kodu pokazuje, jak wyświetlać postęp w polu tekstowym:

Kotlin

currentInputConnection.also { ic: InputConnection ->
    ic.setComposingText("Composi", 1)
    ic.setComposingText("Composin", 1)
    ic.commitText("Composing ", 1)
}

Java

InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
ic.setComposingText("Composin", 1);
ic.commitText("Composing ", 1);

Przechwytywanie kluczowych zdarzeń sprzętowych

Mimo że okno metody wprowadzania nie jest wyraźnie zaznaczone, najpierw otrzymuje ono zdarzenia związane z kluczowymi sprzętami i może je przetwarzać lub przekazywać do aplikacji. Możesz na przykład używać klawiszy kierunkowych do poruszania się w interfejsie i wyboru kandydata podczas tworzenia kompozycji. Możesz też uchwycić klawisz Wstecz, aby zamknąć wszystkie okna dialogowe używane w oknie metody wprowadzania.

Aby przechwytywać klawisze sprzętowe, zastąp wartości onKeyDown() i onKeyUp().

Wywołaj metodę super() w przypadku kluczy, których nie chcesz obsługiwać samodzielnie.

Tworzenie podtypu IME

Podtypy umożliwiają edytorowi IME obsługę wielu trybów wprowadzania i języków obsługiwanych przez ten edytor. Podtyp może reprezentować:

  • ustawienie regionalne, np. pl_PL lub fr_FR;
  • Tryb wprowadzania, np. głos, klawiatura lub pismo odręczne.
  • Inne style wprowadzania, formularze lub właściwości charakterystyczne dla IME, np. układy klawiatury 10-klawiszowe lub QWERTY

Trybem może być dowolny tekst, np. „klawiatura” lub „głos”. Podtyp też może ujawniać kombinację tych wartości.

Informacje o podtypie są używane w oknie przełączania IME, które jest dostępne na pasku powiadomień oraz w ustawieniach IME. Informacje te umożliwiają też bezpośrednie wyświetlenie określonego podtypu IME przez platformę. Kiedy tworzysz edytor IME, korzystaj z podtypu – ułatwia to użytkownikowi rozpoznawanie różnych języków i trybów IME i przełączanie się między nimi.

Zdefiniuj podtypy w jednym z plików zasobów XML metody wprowadzania za pomocą elementu <subtype>. Ten fragment kodu definiuje edytor IME mający dwa podtypy: klawiaturę dla języka angielskiego (USA) i podtyp klawiatury dla języka francuskiego dla Francji:

<input-method xmlns:android="http://schemas.android.com/apk/res/android"
        android:settingsActivity="com.example.softkeyboard.Settings"
        android:icon="@drawable/ime_icon">
    <subtype android:name="@string/display_name_english_keyboard_ime"
            android:icon="@drawable/subtype_icon_english_keyboard_ime"
            android:languageTag="en-US"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="somePrivateOption=true" />
    <subtype android:name="@string/display_name_french_keyboard_ime"
            android:icon="@drawable/subtype_icon_french_keyboard_ime"
            android:languageTag="fr-FR"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="someVariable=30,someInternalOption=false" />
    <subtype android:name="@string/display_name_german_keyboard_ime" ... />
</input-method>

Aby mieć pewność, że Twoje podtypy są prawidłowo oznaczone w interfejsie, użyj „%s” do uzyskania etykiety podtypu, która jest taka sama jak etykieta języka danego podtypu. Zostało to pokazane w 2 kolejnych fragmentach kodu. Pierwszy fragment zawiera część pliku XML metody wprowadzania:

<subtype
    android:label="@string/label_subtype_generic"
    android:imeSubtypeLocale="en_US"
    android:icon="@drawable/icon_en_us"
    android:imeSubtypeMode="keyboard" />

Następny fragment jest częścią pliku strings.xml IME. Zasób ciągu znaków label_subtype_generic, który jest używany przez definicję interfejsu użytkownika metody wprowadzania do ustawiania etykiety podtypu, jest zdefiniowany jako:

<string name="label_subtype_generic">%s</string>

To ustawienie powoduje, że wyświetlana nazwa podtypu odpowiada ustawieniom języka. Na przykład w dowolnym języku angielskim jako wyświetlana nazwa będzie „angielski (Stany Zjednoczone)”.

Wybierz podtypy IME na pasku powiadomień

System Android zarządza wszystkimi podtypami widocznymi przez wszystkie edytory IME. Podtypy IME są traktowane jako tryby edytora IME, do którego należą. Użytkownik może przejść z paska powiadomień lub aplikacji Ustawienia do menu dostępnych podtypów IME, jak pokazano na tej ilustracji:

Obraz przedstawiający menu Systemowe Języki i metody wprowadzania
Rysunek 4. Menu systemowe Języki i metody wprowadzania.

Wybierz podtypy IME z Ustawień systemu

Użytkownik może też kontrolować sposób używania podtypów w panelu Język i wprowadzanie tekstu w ustawieniach systemu:

Obraz przedstawiający menu wyboru języków
Rysunek 5. W menu systemowym Języki

Przełączanie się między podtypami IME

Aby ułatwić użytkownikom przełączanie się między podtypami IME, trzeba użyć klawisza przełączania, takiego jak ikona języka w kształcie kuli ziemskiej na klawiaturze. Zwiększa to jej użyteczność i wygodę. Aby włączyć tę funkcję, wykonaj te czynności:

  1. Zadeklaruj supportsSwitchingToNextInputMethod = "true" w plikach zasobów XML metody wprowadzania. Deklaracja musi wyglądać podobnie do tego fragmentu kodu:
    <input-method xmlns:android="http://schemas.android.com/apk/res/android"
            android:settingsActivity="com.example.softkeyboard.Settings"
            android:icon="@drawable/ime_icon"
            android:supportsSwitchingToNextInputMethod="true">
    
  2. Wywołaj metodę shouldOfferSwitchingToNextInputMethod().
  3. Jeśli metoda zwraca wartość „true” (prawda), wyświetla klucz przełączania.
  4. Gdy użytkownik kliknie klawisz przełączania, wywołaj switchToNextInputMethod() z wartością false (fałsz). Wartość false (fałsz) informuje system, że wszystkie podtypy mają być traktowane jednakowo niezależnie od tego, do jakiego edytora IME należą. Jeśli określisz wartość prawda, system będzie przełączał się między podtypami w bieżącym IME.

Ogólne uwagi o IME

Oto inne kwestie, które warto wziąć pod uwagę podczas wdrażania IME:

  • Zapewnij użytkownikom możliwość ustawiania opcji bezpośrednio w interfejsie IME.
  • Zapewnij użytkownikom możliwość przełączania się na inny edytor IME bezpośrednio z interfejsu metody wprowadzania, ponieważ na urządzeniu może być zainstalowanych wiele edytorów IME.
  • Szybko wyświetl interfejs IME. Wstępnie ładuj lub ładuj na żądanie duże zasoby, aby użytkownicy widzieli edytor IME od razu po kliknięciu pola tekstowego. Buforuj zasoby i widoki na potrzeby kolejnych wywołań metody wprowadzania.
  • Zwolnij duże przydziały pamięci natychmiast po ukryciu okna metody wprowadzania, aby aplikacje miały wystarczającą ilość pamięci do działania. Jeśli edytor IME jest ukryty na kilka sekund, użyj opóźnionej wiadomości, aby zwolnić zasoby.
  • Upewnij się, że użytkownicy mogą wpisać jak najwięcej znaków dla języka lub regionu powiązanych z edytorem IME. Użytkownicy mogą stosować znaki interpunkcyjne w hasłach lub nazwach użytkowników, dlatego edytor IME musi zawierać wiele różnych znaków, aby użytkownicy mogli wpisać hasło i uzyskać dostęp do urządzenia.