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 udostępnianie użytkownikom alternatywnych metod wprowadzania, takich jak klawiatury ekranowe czy wpisywanie głosowe. Po zainstalowaniu edytorów IME użytkownik może wybrać jeden z nich w ustawieniach systemu i używać go w całym systemie. Jednocześnie można włączyć tylko jeden edytor IME.

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

Na tej stronie znajdziesz informacje na te tematy:

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

Cykl życia IME

Poniższy diagram przedstawia cykl życia IME:

Ilustracja przedstawiająca cykl życia IME.
Rysunek 1. Cykl życia IME.

W sekcjach poniżej opisujemy, jak wdrożyć interfejs i kod powiązany z edytorem IME, który jest zgodny 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ę, prosić o niezbędne uprawnienia, zawierać filtr intencji pasujący do działania action.view.InputMethod oraz zawierać metadane określające cechy klawiatury IME. Dodatkowo, aby udostępnić interfejs ustawień, który umożliwia użytkownikowi modyfikowanie działania edytora IME, możesz zdefiniować aktywność „ustawienia”, którą można uruchomić z Ustawień systemu.

Poniższy fragment kodu deklaruje usługę IME. Żąda uprawnienia BIND_INPUT_METHOD umożliwiającego usłudze połączenie IME z systemem, konfiguruje filtr intencji pasujący do działania android.view.InputMethodi definiuje metadane 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>

Kolejny fragment kodu deklaruje aktywność ustawień dla IME. Zawiera filtr intencji dla ACTION_MAIN, który wskazuje, że ta aktywność jest głównym punktem wejścia dla 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ż udostępnić 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 w przypadku znaków klawiatury.

Centralną częścią IME jest komponent usługi, czyli klasa rozszerzająca InputMethodService. Oprócz implementowania normalnego cyklu życia usługi ta klasa ma wywołania zwrotne do udostępniania interfejsu IME, obsługi danych wejściowych użytkownika i przesyłania tekstu do pola, które jest aktywne. Domyślnie klasa InputMethodService zapewnia większość implementacji do zarządzania stanem i widocznością edytora IME oraz komunikacji z bieżącym polem wejściowym.

Ważne są też te klasy:

BaseInputConnection
Określa kanał komunikacji z aplikacji, która otrzymuje dane wejściowe.InputMethod Używasz go do odczytywania tekstu wokół kursora, zatwierdzania tekstu w polu tekstowym i wysyłania do aplikacji surowych zdarzeń klawiszy. Aplikacje muszą rozszerzać tę klasę, a nie implementować interfejsu podstawowegoInputConnection.
KeyboardView
Rozszerzenie View, które wyświetla 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 wpisywania i widok sugestii. 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 wpisuje tekst za pomocą kliknięć klawiszy, pisma odręcznego lub gestów. Gdy IME jest wyświetlany po raz pierwszy, system wywołuje funkcję zwrotną onCreateInputView(). W implementacji tej metody utwórz układ, który chcesz wyświetlić 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 to instancja niestandardowej implementacji KeyboardView, która renderuje Keyboard.

Widok kandydatów

Widok kandydatów to interfejs, w którym IME wyświetla potencjalne poprawki lub sugestie słów, które użytkownik może wybrać. W cyklu życia IME system wywołuje metodę onCreateCandidatesView() gdy jest gotowy do wyświetlenia widoku kandydatów. W implementacji tej metody zwróć układ, który wyświetla sugestie słów, lub wartość null, jeśli nie chcesz niczego wyświetlać. Odpowiedź null jest domyślnym zachowaniem, więc nie musisz jej implementować, jeśli nie podajesz sugestii.

Uwagi dotyczące projektowania interfejsu

W tej sekcji opisujemy niektóre kwestie dotyczące projektowania interfejsu użytkownika dla edytorów IME.

Obsługa wielu rozmiarów ekranu

Interfejs IME musi być skalowalny do różnych rozmiarów ekranu i obsługiwać orientację poziomą oraz pionową. W trybie IME niepełnoekranowym pozostaw wystarczająco dużo miejsca, aby aplikacja mogła wyświetlić pole tekstowe i powiązany z nim kontekst. IME nie powinien zajmować więcej niż połowy ekranu. W trybie pełnoekranowym IME nie stanowi to problemu.

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

Pola tekstowe na Androidzie umożliwiają ustawienie określonego typu danych wejściowych, np. tekst swobodny, liczby, adresy URL, adresy e-mail i ciągi wyszukiwania. Podczas implementacji nowego edytora IME wykrywaj typ danych wejściowych każdego pola i zapewniaj odpowiedni interfejs. Nie musisz jednak konfigurować IME, aby sprawdzać, czy użytkownik wpisuje prawidłowy tekst dla danego typu danych wejściowych. Odpowiedzialność za to ponosi aplikacja, która jest właścicielem pola tekstowego.

Oto na przykład interfejs, który klawiatura IME dla języków europejskich udostępnia na potrzeby wpisywania tekstu na platformie Android:

Ilustracja przedstawiająca wpisywanie tekstu za pomocą edytora IME dla języków opartych na alfabecie łacińskim
Rysunek 2. Wprowadzanie tekstu za pomocą edytora IME dla alfabetu łacińskiego.

Oto interfejs, który klawiatura łacińska udostępnia na platformie Android do wprowadzania danych liczbowych:

Obraz przedstawiający wpisywanie cyfr za pomocą klawiatury IME z alfabetem łacińskim
Rysunek 3. Wpisywanie cyfr za pomocą edytora IME dla języków opartych na alfabecie łacińskim.

Gdy pole wejściowe zostanie aktywowane i uruchomi się edytor IME, system wywoła funkcję onStartInputView(), przekazując obiekt EditorInfo, który zawiera szczegóły dotyczące 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 int, które zawiera wzorce bitowe dla różnych ustawień typu danych wejściowych. Aby przetestować typ danych wejściowych pola tekstowego, zamaskuj go za pomocą stałej 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 widać na ilustracji 3, w przypadku pól tego typu klawiatura IME w języku łacińskim wyświetla klawiaturę numeryczną.
TYPE_CLASS_DATETIME
Pole tekstowe do wpisywania 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ą bardziej szczegółowo opisane w dokumentacji referencyjnej dotyczącej 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 dingbaty zamiast 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 elementu TYPE_CLASS_TEXT służący do wpisywania tekstu, który aplikacja automatycznie uzupełnia na podstawie słownika, wyszukiwania lub innych funkcji.

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

Wysyłanie tekstu do aplikacji

Gdy użytkownik wpisuje 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 użyj instancji InputConnection, aby dostarczyć tekst. Aby uzyskać tę instancję, wywołaj funkcję InputMethodService.getCurrentInputConnection().

Edytowanie tekstu wokół kursora

Podczas edytowania istniejącego tekstu w BaseInputConnection możesz skorzystać z tych przydatnych metod:

getTextBeforeCursor()
Zwraca CharSequence zawierający liczbę żądanych znaków przed bieżącą pozycją kursora.
getTextAfterCursor()
Zwraca CharSequence zawierający liczbę żądanych znaków znajdujących się za bieżącym położeniem kursora.
deleteSurroundingText()
Usuwa określoną liczbę znaków przed i za bieżącą pozycją kursora.
commitText()
Zatwierdza CharSequence w polu tekstowym i ustawia nową pozycję kursora.

Na przykład poniższy fragment kodu 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 kilku czynności w celu utworzenia znaku lub słowa, możesz wyświetlać postęp w polu tekstowym, dopóki użytkownik nie zatwierdzi słowa. Następnie możesz zastąpić częściową kompozycję gotowym tekstem. Możesz wyróżnić tekst, dodając do niego element span, gdy przekazujesz go do funkcji 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 aktywne, najpierw otrzymuje zdarzenia klawiszy sprzętowych i może je wykorzystać lub przekazać do aplikacji. Możesz na przykład używać klawiszy strzałek do poruszania się po interfejsie podczas wybierania kandydatów w trakcie pisania. Możesz też przechwycić naciśnięcie przycisku Wstecz, aby zamknąć okna dialogowe pochodzące z okna metody wprowadzania.

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

W przypadku kluczy, którymi nie chcesz zarządzać samodzielnie, wywołaj metodę super().

Tworzenie podtypu IME

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

  • kod języka, np. en_US lub fr_FR;
  • tryb wprowadzania, np. głosowy, klawiaturowy lub odręczny;
  • inne style, formularze lub właściwości wprowadzania danych specyficzne dla 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 podtypie są używane w oknie przełącznika IME dostępnym na pasku powiadomień i w ustawieniach IME. Informacje te umożliwiają też platformie bezpośrednie wyświetlanie określonego podtypu edytora IME. Podczas tworzenia IME używaj funkcji podtypu, ponieważ pomaga ona użytkownikowi identyfikować i przełączać się między różnymi językami i trybami IME.

Zdefiniuj podtypy w jednym z plików zasobów XML metody wprowadzania, używając elementu <<subtype>>. Poniższy fragment kodu definiuje IME z 2 podtypami: podtyp klawiatury dla języka angielskiego (Stany Zjednoczone) i podtyp 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 ciągu znaków „%s”, aby uzyskać etykietę podtypu, która jest taka sama jak etykieta podtypu w danym języku. Pokazują to 2 kolejne fragmenty 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 edytora IME. Zasób tekstowy label_subtype_generic, który jest używany przez definicję interfejsu 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 ustawieniami regionalnymi. Na przykład w każdej angielskiej wersji językowej 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 edytora 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 ilustracji poniżej:

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ż określić sposób używania podtypów w panelu ustawień Język i wprowadzanie w ustawieniach systemu:

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

Przełączanie między podtypami IME

Możesz umożliwić użytkownikom łatwe przełączanie się między podtypami 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ć 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 klawisz przełączania, wywołanie switchToNextInputMethod(), przekazywanie wartości false. Wartość „false” oznacza, że system ma traktować wszystkie podtypy jednakowo, niezależnie od tego, do jakiego edytora IME należą. Określenie wartości „true” wymaga od systemu przełączania się między podtypami w bieżącym edytorze IME.

Ogólne uwagi dotyczące IME

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

  • Umożliw użytkownikom ustawianie opcji bezpośrednio w interfejsie IME.
  • Umożliw użytkownikom przełączanie się na inny edytor IME bezpośrednio z interfejsu metody wprowadzania, ponieważ na urządzeniu może być zainstalowanych kilka edytorów IME.
  • szybko wyświetlać interfejs IME, Wstępnie wczytuj lub wczytuj na żądanie duże zasoby, aby użytkownicy widzieli IME od razu po kliknięciu pola tekstowego. Pamiętaj w pamięci podręcznej zasoby i widoki 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 IME jest ukryty przez kilka sekund.
  • Upewnij się, że użytkownicy mogą wpisywać jak najwięcej znaków w języku lub ustawieniach regionalnych powiązanych z IME. Użytkownicy mogą używać znaków interpunkcyjnych w hasłach lub nazwach użytkowników, więc IME musi udostępniać wiele różnych znaków, aby umożliwić użytkownikom wpisanie hasła i uzyskanie dostępu do urządzenia.