Utwórz metodę wprowadzania

Edytor metody wprowadzania (IME) to element sterujący, który umożliwia użytkownikom wpisywanie tekstu. Android udostępnia rozszerzalną platformę metod wprowadzania, która umożliwia aplikacjom oferowanie użytkownikom alternatywnych metod wprowadzania, takich jak klawiatury ekranowe czy wprowadzanie mowy. Po zainstalowaniu edytorów IME użytkownik może wybrać jeden z nich w ustawieniach systemowych i używać go w całym systemie. Jednocześnie można włączyć tylko jedną metodę IME.

Aby dodać metodę IME do systemu Android, utwórz aplikację na Androida zawierającą klasę, która rozszerza klasę InputMethodService. Zwykle tworzy się też aktywność „ustawienia”, która przekazuje opcje do usługi IME. Możesz też zdefiniować interfejs ustawień, który będzie wyświetlany jako część ustawień systemu.

Na tej stronie znajdziesz informacje dotyczące tych kwestii:

Jeśli nie masz doświadczenia z edytorami IME, najpierw przeczytaj artykuł wprowadzający Metody wprowadzania na ekranie.

Cykl życia metody IME

Na diagramie poniżej przedstawiono cykl życia metody IME:

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

W sekcjach poniżej opisano, jak wdrożyć interfejs i kod powiązane z edytorem IME, który działa zgodnie z tym cyklem życia.

Deklarowanie komponentów IME w pliku manifestu

W systemie Android IME to aplikacja na Androida, która zawiera specjalną usługę IME. Plik manifestu aplikacji musi deklarować usługę, żądać niezbędnych uprawnień, udostępniać filtr intencji pasujący do działania action.view.InputMethod oraz metadane definiujące cechy metody IME. Dodatkowo, aby udostępnić interfejs ustawień, który umożliwia użytkownikowi modyfikowanie działania metody IME, możesz zdefiniować aktywność „ustawienia”, którą można uruchomić z poziomu ustawień systemowych.

Poniższy fragment kodu deklaruje usługę IME. Żąda uprawnienia BIND_INPUT_METHOD, aby umożliwić usłudze połączenie metody IME z systemem, konfiguruje filtr intencji, który pasuje do działania android.view.InputMethod, i definiuje metadane metody 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 kodu deklaruje aktywność ustawień metody IME. Ma filtr intencji dla ACTION_MAIN, który wskazuje, że ta aktywność jest głównym punktem wejścia do 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ń metody IME bezpośrednio z jej interfejsu.

Interfejs API metody wprowadzania

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

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

Ważne są też te klasy:

BaseInputConnection
Definiuje kanał komunikacji z InputMethod z powrotem do aplikacji, która otrzymuje dane wejściowe. Służy do odczytywania tekstu wokół kursora, zatwierdzania tekstu w polu tekstowym i wysyłania nieprzetworzonych zdarzeń klawiszy do aplikacji. Aplikacje muszą rozszerzać tę klasę, a nie implementować interfejs podstawowy 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żesz zdefiniować w pliku XML.

Projektowanie interfejsu metody wprowadzania

Edytor IME ma 2 główne elementy wizualne: widok wprowadzania i widok propozycji. Musisz wdrożyć tylko te elementy, które są istotne dla projektowanej metody wprowadzania.

Widok danych wejściowych

Widok wprowadzania to interfejs, w którym użytkownik wprowadza tekst w postaci kliknięć klawiszy, pisma odręcznego lub gestów. Gdy edytor IME jest wyświetlany po raz pierwszy, system wywołuje wywołanie zwrotne onCreateInputView(). W implementacji tej metody utwórz układ, który chcesz wyświetlać w oknie IME, i zwróć go do systemu. Poniższy 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 instancją niestandardowej implementacji interfejsu KeyboardView, która renderuje Keyboard.

Widok kandydatów

Widok kandydatów to interfejs, w którym edytor IME wyświetla potencjalne poprawki lub sugestie słów do wyboru przez użytkownika. W cyklu życia edytora IME system wywołuje metodę onCreateCandidatesView(), gdy jest gotowy do wyświetlenia widoku propozycji. W implementacji tej metody zwróć układ, który pokazuje sugestie dotyczące doboru słów, lub zwróć wartość null, jeśli nie chcesz niczego wyświetlać. Odpowiedź null jest działaniem domyślnym, więc nie musisz jej implementować, jeśli nie udostępniasz sugestii.

Uwagi dotyczące projektowania interfejsu

W tej sekcji opisano niektóre kwestie związane z projektowaniem interfejsu metod IME.

Obsługa różnych rozmiarów ekranu

Interfejs metody IME musi być skalowalny i dostosowywać się do różnych rozmiarów ekranu oraz obsługiwać orientację poziomą i pionową. W trybie IME innym niż pełnoekranowy należy pozostawić wystarczająco dużo miejsca, aby aplikacja mogła wyświetlić pole tekstowe i powiązany z nim kontekst, tak aby IME nie zajmował więcej niż połowę ekranu. W trybie pełnoekranowym edytora IME nie jest to problemem.

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

Pola tekstowe na Androidzie umożliwiają ustawienie określonego typu danych wejściowych, takich jak tekst w formie swobodnej, liczby, adresy URL, adresy e-mail i ciągi wyszukiwania. Podczas wdrażania nowej metody IME wykryj typ danych wejściowych każdego pola i udostępnij odpowiedni interfejs. Nie musisz jednak konfigurować edytora IME, aby sprawdzać, czy użytkownik wpisuje prawidłowy tekst dla danego typu danych wejściowych. Odpowiada za to aplikacja, która jest właścicielem pola tekstowego.

Oto na przykład interfejs, który metoda wprowadzania znaków łacińskich udostępnia do wprowadzania tekstu na platformie Androida:

Obraz przedstawiający wprowadzanie tekstu w metodzie wprowadzania znaków łacińskich
Rysunek 2. Wprowadzanie tekstu za pomocą metody IME dla alfabetu łacińskiego.

Oto interfejs, który metoda wprowadzania znaków łacińskich udostępnia na platformie Androida do wprowadzania liczb:

Obraz przedstawiający wprowadzanie cyfr w metodzie wprowadzania znaków łacińskich
Rysunek 3. Wprowadzanie cyfr za pomocą metody wprowadzania znaków łacińskich.

Gdy pole do wprowadzania danych zostanie zaznaczone i uruchomi się edytor IME, system wywołuje metodę onStartInputView(), przekazując obiekt EditorInfo, który zawiera szczegółowe 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 int, które zawiera wzorce bitowe dla różnych ustawień typu danych wejściowych. Aby przetestować go pod kątem typu danych wejściowych pola tekstowego, zamaskuj go stałą TYPE_MASK_CLASS, na przykład tak:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

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

TYPE_CLASS_NUMBER
Pole tekstowe do wpisywania liczb. Jak pokazano na rysunku 3, metoda wprowadzania znaków łacińskich wyświetla klawiaturę numeryczną w przypadku pól tego typu.
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 dowolnych obsługiwanych znaków.

Te stałe są opisane bardziej szczegółowo w dokumentacji referencyjnej InputType.

Pole inputType może zawierać inne bity, które wskazują wariant typu pola tekstowego, np.:

TYPE_TEXT_VARIATION_PASSWORD
Wariant TYPE_CLASS_TEXT do wpisywania haseł. Metoda wprowadzania wyświetla znaki dingbat zamiast rzeczywistego tekstu.
TYPE_TEXT_VARIATION_URI
Wariant TYPE_CLASS_TEXT do wpisywania adresów URL i innych identyfikatorów URI.
TYPE_TEXT_FLAG_AUTO_COMPLETE
Wariant TYPE_CLASS_TEXT do wpisywania tekstu, który aplikacja automatycznie uzupełnia na podstawie słownika, wyszukiwania lub innego narzędzia.

Podczas testowania tych wariantów maskuj inputType odpowiednią stałą. Dostępne stałe masek są wymienione w dokumentacji referencyjnej InputType.

Wyślij tekst do aplikacji

Gdy użytkownik wprowadza tekst za pomocą edytora IME, możesz wysyłać tekst do aplikacji, wysyłając poszczególne zdarzenia klawiszy lub edytując tekst wokół kursora w polu tekstowym aplikacji. W obu przypadkach do dostarczenia tekstu użyj instancji InputConnection. Aby uzyskać tę instancję, wywołaj InputMethodService.getCurrentInputConnection().

Edytowanie tekstu wokół kursora

Podczas edytowania istniejącego tekstu przydatne mogą być te metody w klasie BaseInputConnection:

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

Poniższy fragment kodu pokazuje na przykład, jak zastąpić 4 znaki po lewej stronie kursora tekstem „Cześć!”:

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 kilku czynności, aby utworzyć glif lub słowo, możesz wyświetlać postęp w polu tekstowym, dopóki użytkownik nie zatwierdzi słowa, a następnie zastąpić częściowo utworzony tekst gotowym. Możesz nadać tekstowi specjalny format, dodając do niego span podczas przekazywania do setComposingText().

Poniższy 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 zdarzeń klawiszy sprzętowych

Mimo że okno metody wprowadzania nie jest bezpośrednio aktywne, najpierw odbiera zdarzenia klawiszy sprzętowych i może je wykorzystać lub przekazać do aplikacji. Możesz na przykład użyć klawiszy kierunkowych do poruszania się po interfejsie w celu wyboru kandydata podczas tworzenia wiadomości. Możesz też przechwycić klawisz Wstecz, aby zamknąć wszystkie okna dialogowe pochodzące z okna metody wprowadzania.

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

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

Tworzenie podtypu IME

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

  • język, np. en_US lub fr_FR;
  • tryb wprowadzania, np. głosowo, za pomocą klawiatury lub odręcznie;
  • inne style, formy lub właściwości wprowadzania danych specyficzne dla metody IME, takie jak układy klawiatury 10-klawiszowej lub QWERTY.

Tryb może być dowolnym tekstem, np. „klawiatura” lub „głos”. Podtyp może też udostępniać kombinację tych elementów.

Informacje o podtypach są używane w oknie przełącznika IME, które jest dostępne na pasku powiadomień, oraz w ustawieniach IME. Te informacje umożliwiają też platformie bezpośrednie wywołanie konkretnego podtypu metody IME. Podczas tworzenia edytora IME użyj funkcji podtypu, ponieważ pomaga ona użytkownikowi identyfikować i przełączać się między różnymi językami i trybami edytora IME.

Zdefiniuj podtypy w jednym z plików zasobów XML metody wprowadzania, używając elementu <subtype>. Poniższy 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żyj `%s`, aby uzyskać etykietę podtypu, która jest taka sama jak etykieta języka podtypu. Zostało to przedstawione w 2 kolejnych fragmentach kodu. Pierwszy fragment kodu pokazuje 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" />

Kolejny fragment pochodzi z pliku strings.xml IME. Zasób tekstowy label_subtype_generic, który jest używany przez definicję interfejsu metody wprowadzania do ustawienia 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 języka. Na przykład w przypadku dowolnych ustawień regionalnych języka angielskiego wyświetlana nazwa to „English (United States)”.

Wybieranie podtypów IME na pasku powiadomień

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

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

Wybieranie podtypów IME w ustawieniach systemu

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

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

Przełączanie się między podtypami metody IME

Możesz ułatwić użytkownikom przełączanie się między podtypami metody IME, udostępniając klawisz przełączania, np. ikonę języka w kształcie kuli ziemskiej na klawiaturze. Zwiększa to użyteczność klawiatury i jest wygodne dla użytkownika. Aby włączyć to przełączanie, 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 zwróci wartość true, wyświetl przycisk przełączania.
  4. Gdy użytkownik kliknie przycisk przełączania, wywołaj switchToNextInputMethod(), przekazując wartość false. Wartość false informuje system, że wszystkie podtypy mają być traktowane jednakowo, niezależnie od tego, do jakiej metody IME należą. Jeśli ustawisz wartość „true”, system będzie musiał przełączać się między podtypami w bieżącej metodzie IME.

Uwagi ogólne dotyczące edytorów 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 edytora IME.
  • Zapewnij użytkownikom możliwość przełączenia się na inną metodę IME bezpośrednio z interfejsu metody wprowadzania, ponieważ na urządzeniu może być zainstalowanych kilka metod IME.
  • Szybkie wyświetlanie interfejsu edytora IME. Wstępnie wczytuj lub wczytuj na żądanie duże zasoby, aby użytkownicy widzieli edytor IME, gdy tylko klikną pole tekstowe. Zasoby i widoki pamięci podręcznej na potrzeby kolejnych wywołań metody wprowadzania.
  • Zwalniaj duże alokacje 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, aby zwolnić zasoby, jeśli edytor IME jest ukryty przez kilka sekund.
  • Upewnij się, że użytkownicy mogą wpisać jak najwięcej znaków w języku lub regionie powiązanym z edytorem IME. Użytkownicy mogą używać znaków interpunkcyjnych w hasłach lub nazwach użytkownika, więc edytor IME musi udostępniać wiele różnych znaków, aby umożliwić użytkownikom wpisanie hasła i uzyskanie dostępu do urządzenia.