Utwórz metodę wprowadzania

Edytor metody wprowadzania (IME) to element sterujący, który umożliwia użytkownikowi wpisywanie tekstu. Android udostępnia rozszerzalną platformę metod wprowadzania, dzięki której aplikacje mogą udostępniać użytkownikom alternatywne metody wprowadzania, np. klawiaturę ekranową lub wprowadzanie głosowe. Po zainstalowaniu edytorów IME użytkownik może je wybrać w ustawieniach systemu i używać 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ę rozszerzającą InputMethodService. Poza tym zwykle tworzysz „ustawienia” działania, które przekazuje opcje do usługi IME. Możesz też określić interfejs ustawień, który będzie się wyświetlać w ramach ustawień systemu.

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

Jeśli nie znasz jeszcze edytorów IME, przeczytaj najpierw artykuł wprowadzający Metody wprowadzania na ekranie.

Cykl życia IME

Poniższy diagram przedstawia cykl życia IME:

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

W poniższych sekcjach znajdziesz informacje o tym, jak wdrożyć interfejs i kod powiązany z edytorem IME, który jest zgodny z tym cyklem życia.

Zadeklaruj komponenty IME w pliku manifestu

W systemie Android jest to aplikacja na Androida zawierająca specjalną usługę IME. Plik manifestu aplikacji musi deklarować usługę, prosić o niezbędne uprawnienia, zawierać filtr intencji pasujący do działania action.view.InputMethod i zawierać metadane określające cechy edytora IME. Aby udostępnić interfejs ustawień, który pozwala użytkownikowi modyfikować działanie IME, możesz zdefiniować działanie „ustawień”, które można uruchamiać w Ustawieniach systemu.

Ten fragment deklaruje usługę IME. Żąda uprawnienia BIND_INPUT_METHOD umożliwiające usłudze połączenie IME z systemem, konfiguruje filtr intencji pasujący do działania android.view.InputMethod i określa metadane dla 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 deklaruje aktywność związaną z ustawieniami dla IME. Zawiera filtr intencji 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ż przyznać dostęp do ustawień IME bezpośrednio z jego interfejsu.

Interfejs API metody wprowadzania

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

Centralną częścią IME jest komponent usługi – klasa, która rozszerza InputMethodService. Oprócz wdrożenia normalnego cyklu życia usługi ta klasa zawiera wywołania zwrotne do udostępniania interfejsu IME, obsługi danych wejściowych użytkownika i dostarczania tekstu do wyróżnionego pola. Domyślnie klasa InputMethodService zapewnia większość implementacji do zarządzania stanem i widocznością IME oraz komunikowania się z bieżącym polem do wprowadzania danych.

Ważne są również te klasy:

BaseInputConnection
Określa kanał komunikacji od InputMethod z powrotem do aplikacji, która otrzymuje dane wejściowe. Umożliwia on odczytywanie tekstu wokół kursora, zatwierdzanie tekstu w polu tekstowym i wysyłanie nieprzetworzonych kluczowych zdarzeń do aplikacji. Aplikacje muszą rozszerzać tę klasę, a nie implementować interfejsu podstawowego 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 UI metody wprowadzania

W przypadku IME są 2 główne elementy wizualne: widok input i widok kandydatów. Musisz wdrożyć tylko te elementy, które pasują do projektowanej metody wprowadzania.

Widok danych wejściowych

Widok danych wejściowych to interfejs, w którym użytkownik wpisuje tekst, stosując kliknięcia klawiszy, pismo odręczne lub gesty. Po pierwszym wyświetleniu edytora IME system wywołuje wywołanie zwrotne onCreateInputView(). W ramach implementacji tej metody utwórz układ, który chcesz wyświetlić w oknie IME, a potem wróć do systemu. Ten fragment kodu zawiera 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 to instancja niestandardowej implementacji obiektu KeyboardView, która renderuje żądanie Keyboard.

Widok kandydatów

Widok kandydatów to interfejs, w którym IME wyświetla potencjalne poprawki słów lub sugestie do wyboru przez użytkownika. W cyklu życia IME system wywołuje onCreateCandidatesView(), gdy wszystko jest gotowe do wyświetlenia widoku kandydatów. W implementacji tej metody zwracaj układ z sugestiami słów lub zwracaj wartość null, jeśli nie chcesz niczego wyświetlać. Odpowiedź o wartości null jest zachowaniem domyślnym, więc nie musisz jej wdrażać, jeśli nie podasz sugestii.

Uwagi na temat projektowania interfejsu

W tej sekcji opisujemy wybrane aspekty projektowania UI w edytorach IME.

Obsługa różnych rozmiarów ekranu

Interfejs użytkownika edytora IME musi być w stanie skalować się do różnych rozmiarów ekranu oraz obsługiwać zarówno orientację poziomą, jak i pionową. W trybie niepełnoekranowym należy zostawić w aplikacji wystarczającą ilość miejsca na wyświetlenie pola tekstowego i powiązanego z nim kontekstu, tak aby edytor nie zajmował więcej niż połowę ekranu. W trybie pełnoekranowym nie jest to problemem.

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

Pola tekstowe Androida umożliwiają ustawienie określonego typu danych wejściowych, np. dowolnego tekstu, liczb, adresów URL, adresów e-mail i wyszukiwanych ciągów znaków. Przy wdrażaniu nowego edytora IME wykrywaj typ danych wejściowych w każdym polu i udostępniaj dla niego odpowiedni interfejs. Nie musisz jednak konfigurować edytora IME, aby sprawdzać, czy użytkownik wpisuje prawidłowy tekst dla danego typu danych wejściowych. Odpowiada to aplikacji, do której należy pole tekstowe.

Tak na przykład interfejs udostępniany przez edytor IME dla języka łacińskiego do wprowadzania tekstu na platformie Androida:

Obraz przedstawiający dane wejściowe w edytorze IME łacińskiego
Rysunek 2. Wprowadzanie tekstu w edytorze łacińskim IME.

A oto interfejs udostępniany przez Latin IME do wprowadzania liczbowych danych na platformie Androida:

Obraz przedstawiający dane liczbowe na łacińskim edytorze IME
Rysunek 3. Kodowanie liczbowe IME dla alfabetu łacińskiego.

Gdy pole do wprowadzania danych zostanie zaznaczone, a edytor IME uruchomi się, system wywoła onStartInputView(), przesyłając obiekt EditorInfo zawierający informacje o typie danych wejściowych i inne atrybuty pola tekstowego. W tym obiekcie pole inputType zawiera typ danych wejściowych pola tekstowego.

Pole inputType to pole int, które zawiera wzorce bitowe dla różnych ustawień typów danych wejściowych. Aby przetestować go pod kątem typu danych wejściowych pola tekstowego, zamaskuj go za pomocą stałej TYPE_MASK_CLASS w ten sposób:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

Wzorzec bitowy typu wejściowego może mieć jedną z kilku wartości, w tym:

TYPE_CLASS_NUMBER
Pole tekstowe do wpisywania numerów. Jak widać na ilustracji 3, edytor IME dla alfabetów łacińskich wyświetla w polach tego typu klawiaturę numeryczną.
TYPE_CLASS_DATETIME
Pole tekstowe do wpisania daty i godziny.
TYPE_CLASS_PHONE
Pole tekstowe do wpisania numerów telefonów.
TYPE_CLASS_TEXT
Pole tekstowe do wpisania obsługiwanych znaków.

Bardziej szczegółowe informacje o tych stałych znajdziesz 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 zamiast tekstu powoduje wyświetlanie znaków dingbatów.
TYPE_TEXT_VARIATION_URI
Wariant TYPE_CLASS_TEXT do wpisywania adresów URL i innych identyfikatorów URI.
TYPE_TEXT_FLAG_AUTO_COMPLETE
Wariant funkcji TYPE_CLASS_TEXT do wpisywania tekstu, który aplikacja automatycznie uzupełnia w słowniku, wyszukiwarce lub innej usłudze.

Podczas testowania tych wariantów maskuj inputType za pomocą odpowiedniej stałej. Dostępne stałe maski znajdziesz w dokumentacji referencyjnej InputType.

Wyślij tekst do aplikacji

Kiedy użytkownik wpisuje tekst za pomocą IME, możesz wysyłać go do aplikacji, wysyłając poszczególne kluczowe zdarzenia lub edytując tekst wokół kursora w polu tekstowym aplikacji. W obu przypadkach użyj instancji InputConnection, aby przekazać tekst. Aby pobrać tę instancję, wywołaj InputMethodService.getCurrentInputConnection().

Edytowanie tekstu wokół kursora

Gdy edytujesz dotychczasowy tekst, możesz w BaseInputConnection stosować te metody:

getTextBeforeCursor()
Zwraca CharSequence, który zawiera liczbę żądanych znaków przed bieżącą pozycją kursora.
getTextAfterCursor()
Zwraca CharSequence, który zawiera liczbę żądanych znaków następujących po bieżącej pozycji kursora.
deleteSurroundingText()
Usuwa określoną liczbę znaków przed bieżącą pozycją kursora i po niej.
commitText()
Przypisuje element CharSequence do pola tekstowego i ustawia nową pozycję kursora.

Na przykład ten fragment kodu pokazuje, jak zamienić cztery 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);

Ułatw tworzenie tekstu przed zatwierdzeniem

Jeśli edytor IME przewiduje tekst lub wymaga wielu kroków, by utworzyć glif lub słowo, możesz pokazywać postęp w polu tekstowym, dopóki użytkownik nie zapisze danego słowa. Dzięki temu możesz zastąpić fragment tekstu gotowym tekstem. Możesz nadać tekstowi specjalne podejście, dodając do niego span, gdy przekazujesz go do funkcji setComposingText().

Ten fragment kodu pokazuje, jak wyświetlić 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ń dotyczących sprzętu

Mimo że okno metody wprowadzania nie jest wyraźnie zaznaczone, otrzymuje najpierw kluczowe zdarzenia sprzętowe i może je wykorzystać lub przekazać do aplikacji. Możesz na przykład używać klawiszy strzałek, aby poruszać się po interfejsie w celu wyboru kandydatów podczas tworzenia kompozycji. Możesz też przechwycić klawisz Wstecz, aby zamknąć wszystkie okna dialogowe pochodzące z okna metody wprowadzania.

Aby przechwytywać klucze sprzętowe, zastąp ustawienia onKeyDown() i onKeyUp().

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

Tworzenie podtypu IME

Dzięki podtypom edytor IME może wyświetlać wiele trybów wprowadzania i języków obsługiwanych przez dany edytor. Podtyp może obejmować:

  • Region, np. pl_PL lub fr_FR
  • trybu wprowadzania danych, takiego jak głos, klawiatura lub pismo odręczne;
  • inne style, formularze lub właściwości specyficzne dla IME, np. 10-klawiszowy lub QWERTY układ klawiatury

Tryb może zawierać dowolny tekst, np. „klawiatura” lub „głos”. Podtyp może też ujawniać ich kombinację.

Informacje o podtypie są używane w oknie przełączania IME, które jest dostępne na pasku powiadomień oraz w ustawieniach IME. Te informacje umożliwiają też platformie bezpośrednie wywołanie określonego podtypu IME. Podczas tworzenia edytora IME używaj podtypu lokalizacji, ponieważ ułatwia on użytkownikowi rozpoznawanie różnych języków i trybów IME oraz przełączanie się między nimi.

Zdefiniuj podtypy w jednym z plików zasobów XML metody wejściowej za pomocą elementu <subtype>. Ten fragment kodu definiuje edytor IME z 2 podtypami: podtypem klawiatury dla języka angielskiego (USA) i podtypem klawiatury dla języka francuskiego (Francja):

<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 podtypy są prawidłowo oznaczone w interfejsie użytkownika, użyj parametru „%s”, aby uzyskać etykietę podtypu, która jest taka sama jak etykieta języka podtypu. Dowiesz się o tym w kolejnych 2 kolejnych fragmentach kodu. Pierwszy fragment kodu pokazuje część pliku XML metody przesyłania:

<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 w definicji interfejsu użytkownika metody wprowadzania do ustawiania etykiety podtypu, jest zdefiniowany w ten sposób:

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

To ustawienie powoduje, że wyświetlana nazwa podtypu jest zgodna z ustawieniem lokalnym. Na przykład w każdym języku polskim wyświetlana nazwa to „English (Stany Zjednoczone)”.

Wybierz podtypy IME na pasku powiadomień

System Android zarządza wszystkimi podtypami udostępnianymi przez wszystkie edytory IME. Podtypy IME są traktowane jako tryby IME, do których należą. Użytkownik może przejść z paska powiadomień lub aplikacji Ustawienia do menu z dostępnymi podtypami IME, jak pokazano na tym rysunku:

Ilustracja pokazująca menu systemowe Języki i metody wprowadzania
Rysunek 4. Menu systemowe Języki i metody wprowadzania.

Wybierz podtypy IME w ustawieniach systemu

Użytkownik może też określić sposób używania podtypów w panelu Język i wprowadzanie tekstu w ustawieniach systemowych:

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

Przełączanie między podtypami IME

Aby ułatwić użytkownikom przełączanie się między podtypami IME, możesz ustawić klawisz przełączania, np. ikonę języka w kształcie kuli ziemskiej na klawiaturze. Zwiększa to użyteczność klawiatury i jest wygodniejsze dla użytkownika. Aby włączyć tę funkcję, wykonaj te czynności:

  1. Zadeklaruj supportsSwitchingToNextInputMethod = "true" w plikach zasobów XML metody wprowadzania. Twoja 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ść „prawda”, wyświetl klucz przełączania.
  4. Gdy użytkownik naciśnie klawisz przełączania, wywoła polecenie switchToNextInputMethod(), przekazując wartość fałsz. Wartość fałsz informuje system, że wszystkie podtypy są traktowane jednakowo niezależnie od tego, do którego IME należą. Ustawienie wartości „true” (prawda) wymaga, aby system przełączał się między podtypami w bieżącym edytorze IME.

Ogólne uwagi na temat IME

Oto co jeszcze musisz wziąć pod uwagę podczas implementacji 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 IME.
  • Szybko wyświetl interfejs IME. Wstępnie ładuj lub wczytuj na żądanie duże zasoby, by użytkownicy mogli zobaczyć edytor IME zaraz po kliknięciu pola tekstowego. Buforuj zasoby i widoki na potrzeby kolejnych wywołań metody wejściowej.
  • 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. Użyj opóźnionej wiadomości do zwolnienia zasobów, jeśli edytor IME jest ukryty na kilka sekund.
  • Użytkownicy powinni wpisać jak najwięcej znaków dla języka lub regionu powiązanego z 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 umożliwić użytkownikom wpisanie hasła i uzyskanie dostępu do urządzenia.