Создать метод ввода

Редактор методов ввода (IME) — это пользовательский элемент управления, позволяющий пользователям вводить текст. Android предоставляет расширяемую структуру методов ввода, которая позволяет приложениям предоставлять пользователям альтернативные методы ввода, такие как экранные клавиатуры или речевой ввод. После установки IME пользователь может выбрать один из системных настроек и использовать его во всей системе. Одновременно может быть включен только один IME.

Чтобы добавить IME в систему Android, создайте приложение Android, содержащее класс, расширяющий InputMethodService . Кроме того, вы обычно создаете действие «настроек», которое передает параметры службе IME. Вы также можете определить пользовательский интерфейс настроек, который отображается как часть системных настроек.

На этой странице рассматриваются следующие темы:

Если вы не работали с редакторами метода ввода, сначала прочтите вводную статью «Способы экранного ввода» .

Жизненный цикл IME

Следующая диаграмма описывает жизненный цикл IME:

Изображение, демонстрирующее жизненный цикл IME.
Рисунок 1. Жизненный цикл IME.

В следующих разделах описывается, как реализовать пользовательский интерфейс и код, связанный с IME, который следует этому жизненному циклу.

Объявите компоненты IME в манифесте

В системе Android IME — это приложение Android, которое содержит специальную службу IME. Файл манифеста приложения должен объявлять службу, запрашивать необходимые разрешения, предоставлять фильтр намерений, который соответствует действию action.view.InputMethod , и предоставлять метаданные, которые определяют характеристики IME. Кроме того, чтобы предоставить интерфейс настроек, который позволяет пользователю изменять поведение IME, вы можете определить действие «настройки», которое может быть запущено из Системных настроек.

Следующий фрагмент объявляет службу IME. Он запрашивает разрешение BIND_INPUT_METHOD , чтобы позволить службе подключить IME к системе, устанавливает фильтр намерений, который соответствует действию android.view.InputMethod , и определяет метаданные для 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>

Следующий фрагмент объявляет настройки активности для IME. Он имеет фильтр намерений для ACTION_MAIN , который указывает, что эта активность является основной точкой входа для приложения 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>

Вы также можете предоставить доступ к настройкам IME непосредственно из его пользовательского интерфейса.

API метода ввода

Классы, специфичные для IME, находятся в пакетах android.inputmethodservice и android.view.inputmethod . Класс KeyEvent важен для обработки символов клавиатуры.

Центральная часть IME — это компонент службы — класс, расширяющий InputMethodService . Помимо реализации обычного жизненного цикла службы, этот класс имеет обратные вызовы для предоставления пользовательского интерфейса вашего IME, обработки пользовательского ввода и доставки текста в поле, имеющее фокус. По умолчанию класс InputMethodService обеспечивает большую часть реализации для управления состоянием и видимостью IME и взаимодействия с текущим полем ввода.

Также важны следующие классы:

BaseInputConnection
Определяет канал связи от InputMethod обратно к приложению, которое получает его ввод. Вы используете его для чтения текста вокруг курсора, фиксации текста в текстовом поле и отправки необработанных ключевых событий в приложение. Приложения должны расширять этот класс, а не реализовывать базовый интерфейс InputConnection .
KeyboardView
Расширение View , которое отображает клавиатуру и реагирует на события пользовательского ввода. Раскладка клавиатуры задается экземпляром Keyboard , который можно определить в XML-файле.

Разработать пользовательский интерфейс метода ввода

Для IME есть два основных визуальных элемента: представление ввода и представление кандидатов . Вам нужно реализовать только те элементы, которые имеют отношение к методу ввода, который вы разрабатываете.

Входной вид

Представление ввода — это пользовательский интерфейс, в котором пользователь вводит текст в виде нажатия клавиш, рукописного ввода или жестов. Когда IME отображается в первый раз, система вызывает обратный вызов onCreateInputView() . В своей реализации этого метода создайте макет, который вы хотите отобразить в окне IME, и верните макет системе. В следующем фрагменте показан пример реализации метода onCreateInputView() :

Котлин

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

Ява

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

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

    return inputView;
}

В этом примере MyKeyboardView — это экземпляр пользовательской реализации KeyboardView , которая отображает Keyboard .

Просмотр кандидатов

Представление кандидатов — это пользовательский интерфейс, в котором IME отображает потенциальные исправления слов или предложения для выбора пользователем. В жизненном цикле IME система вызывает onCreateCandidatesView() , когда она готова отобразить представление кандидатов. В вашей реализации этого метода верните макет, который показывает предложения слов, или верните null, если вы не хотите ничего показывать. Нулевой ответ — это поведение по умолчанию, поэтому вам не нужно реализовывать это, если вы не предоставляете предложения.

Аспекты дизайна пользовательского интерфейса

В этом разделе описываются некоторые соображения по проектированию пользовательского интерфейса для IME.

Поддержка экранов разных размеров

Пользовательский интерфейс вашего IME должен иметь возможность масштабирования для разных размеров экрана и обрабатывать как альбомную, так и портретную ориентацию. В неполноэкранном режиме IME оставьте достаточно места для отображения текстового поля и любого связанного контекста, чтобы IME занимал не более половины экрана. В полноэкранном режиме IME это не проблема.

Обработка различных типов входных данных

Текстовые поля Android позволяют вам задать определенный тип ввода, например, текст в свободной форме, числа, URL-адреса, адреса электронной почты и строки поиска. При реализации нового IME определите тип ввода каждого поля и предоставьте для него соответствующий интерфейс. Однако вам не нужно настраивать IME для проверки того, вводит ли пользователь допустимый текст для типа ввода. Это ответственность приложения, которому принадлежит текстовое поле.

Например, вот интерфейс, который Latin IME предоставляет для ввода текста на платформе Android:

Изображение, показывающее ввод текста в Latin IME
Рисунок 2. Ввод текста латиницей IME.

А вот интерфейс, который Latin IME предоставляет для числового ввода на платформе Android:

Изображение, демонстрирующее ввод чисел в редакторе ввода текста на латинице
Рисунок 3. Ввод чисел в латинском IME.

Когда поле ввода получает фокус и запускается ваш IME, система вызывает onStartInputView() , передавая объект EditorInfo , содержащий сведения о типе ввода и других атрибутах текстового поля. В этом объекте поле inputType содержит тип ввода текстового поля.

Поле inputType — это int , которое содержит битовые шаблоны для различных настроек типа ввода. Чтобы проверить его на тип ввода текстового поля, замаскируйте его константой TYPE_MASK_CLASS , например:

Котлин

inputType and InputType.TYPE_MASK_CLASS

Ява

inputType & InputType.TYPE_MASK_CLASS

Битовая комбинация входного типа может иметь одно из нескольких значений, включая:

TYPE_CLASS_NUMBER
Текстовое поле для ввода цифр. Как показано на рисунке 3, Latin IME отображает цифровую клавиатуру для полей этого типа.
TYPE_CLASS_DATETIME
Текстовое поле для ввода даты и времени.
TYPE_CLASS_PHONE
Текстовое поле для ввода телефонных номеров.
TYPE_CLASS_TEXT
Текстовое поле для ввода любых поддерживаемых символов.

Более подробно эти константы описаны в справочной документации по InputType .

Поле inputType может содержать другие биты, указывающие вариант типа текстового поля, например:

TYPE_TEXT_VARIATION_PASSWORD
Вариант TYPE_CLASS_TEXT для ввода паролей. Метод ввода отображает дингбаты вместо реального текста.
TYPE_TEXT_VARIATION_URI
Вариант TYPE_CLASS_TEXT для ввода веб-URL-адресов и других унифицированных идентификаторов ресурсов (URI).
TYPE_TEXT_FLAG_AUTO_COMPLETE
Вариант TYPE_CLASS_TEXT для ввода текста, который приложение автоматически заполняет из словаря, поиска или другого средства.

Маскируйте inputType соответствующей константой при тестировании этих вариантов. Доступные константы маски перечислены в справочной документации для InputType .

Отправить текст в приложение

Когда пользователь вводит текст с помощью вашего IME, вы можете отправлять текст в приложение, отправляя отдельные ключевые события или редактируя текст вокруг курсора в текстовом поле приложения. В любом случае используйте экземпляр InputConnection для доставки текста. Чтобы получить этот экземпляр, вызовите InputMethodService.getCurrentInputConnection() .

Редактировать текст вокруг курсора

При редактировании существующего текста в BaseInputConnection полезны следующие методы:

getTextBeforeCursor()
Возвращает CharSequence , содержащий количество запрошенных символов перед текущей позицией курсора.
getTextAfterCursor()
Возвращает CharSequence , содержащий количество запрошенных символов, следующих за текущей позицией курсора.
deleteSurroundingText()
Удаляет указанное количество символов до и после текущей позиции курсора.
commitText()
Фиксирует CharSequence в текстовом поле и устанавливает новую позицию курсора.

Например, следующий фрагмент показывает, как заменить четыре символа слева от курсора текстом «Привет!»:

Котлин

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

Ява

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

Поддержка написания текста перед фиксацией

Если ваш IME предсказывает текст или требует нескольких шагов для составления глифа или слова, вы можете показывать прогресс в текстовом поле, пока пользователь не зафиксирует слово, а затем вы можете заменить частичное составление завершенным текстом. Вы можете дать тексту особую обработку, добавив к нему интервал при передаче его в setComposingText() .

В следующем фрагменте показано, как отобразить ход выполнения в текстовом поле:

Котлин

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

Ява

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

Перехват событий аппаратных ключей

Несмотря на то, что окно метода ввода не имеет явного фокуса, оно сначала получает события аппаратных клавиш и может потреблять их или пересылать в приложение. Например, вы можете захотеть использовать клавиши направления для навигации в вашем пользовательском интерфейсе для выбора кандидатов во время составления. Вы также можете захотеть перехватить клавишу «Назад», чтобы закрыть любые диалоги, исходящие из окна метода ввода.

Для перехвата аппаратных клавиш переопределите onKeyDown() и onKeyUp() .

Вызовите метод super() для ключей, которые вы не хотите обрабатывать самостоятельно.

Создать подтип IME

Подтипы позволяют IME раскрывать несколько режимов ввода и языков, поддерживаемых IME. Подтип может представлять следующее:

  • Локаль, например en_US или fr_FR
  • Режим ввода, например, голос, клавиатура или рукописный ввод
  • Другие стили ввода, формы или свойства, характерные для IME, такие как 10-клавишная или QWERTY-раскладка клавиатуры.

Режим может быть любым текстом, например «клавиатура» или «голос». Подтип также может представлять собой комбинацию из них.

Информация о подтипе используется для диалога переключателя IME, который доступен из панели уведомлений, и для настроек IME. Эта информация также позволяет фреймворку напрямую вызывать определенный подтип IME. При создании IME используйте функцию подтипа, поскольку она помогает пользователю идентифицировать и переключаться между различными языками и режимами IME.

Определите подтипы в одном из файлов ресурсов XML метода ввода, используя элемент <subtype> . Следующий фрагмент кода определяет IME с двумя подтипами: подтип клавиатуры для локали американского английского и другой подтип клавиатуры для локали французского языка для Франции:

<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>

Чтобы убедиться, что ваши подтипы правильно помечены в пользовательском интерфейсе, используйте `%s`, чтобы получить метку подтипа, которая совпадает с меткой локали подтипа. Это показано в следующих двух фрагментах кода. Первый фрагмент показывает часть XML-файла метода ввода:

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

Следующий фрагмент является частью файла strings.xml редактора ввода. Строковый ресурс label_subtype_generic , который используется определением пользовательского интерфейса метода ввода для установки метки подтипа, определяется следующим образом:

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

Эта настройка заставляет отображаемое имя подтипа соответствовать настройкам локали. Например, в любой английской локали отображаемое имя — «English (United States)».

Выберите подтипы IME на панели уведомлений.

Система Android управляет всеми подтипами, представленными всеми IME. Подтипы IME рассматриваются как режимы IME, к которым они принадлежат. Пользователь может перейти из панели уведомлений или приложения «Настройки» в меню доступных подтипов IME, как показано на следующем рисунке:

Изображение, показывающее меню «Языки и система ввода»
Рисунок 4. Меню «Языки и система ввода ».

Выберите подтипы IME в настройках системы.

Пользователь также может управлять использованием подтипов на панели «Настройки языка и ввода » в системных настройках:

Изображение, показывающее меню выбора языков
Рисунок 5. Системное меню « Языки»

Переключение между подтипами IME

Вы можете позволить пользователям легко переключаться между подтипами IME, предоставив клавишу переключения, например, значок языка в форме глобуса на клавиатуре. Это повышает удобство использования клавиатуры и удобно для пользователя. Чтобы включить это переключение, выполните следующие действия:

  1. Объявите supportsSwitchingToNextInputMethod = "true" в файлах ресурсов XML метода ввода. Ваше объявление должно выглядеть примерно так, как в следующем фрагменте кода:
    <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. Вызовите метод shouldOfferSwitchingToNextInputMethod() .
  3. Если метод возвращает значение true, отобразите клавишу переключения.
  4. Когда пользователь нажимает клавишу переключения, вызывается switchToNextInputMethod() , передавая false. Значение false сообщает системе, что все подтипы следует обрабатывать одинаково, независимо от того, к какому IME они принадлежат. Указание true требует, чтобы система циклически перебирала подтипы в текущем IME.

Общие соображения по IME

Вот еще несколько моментов, которые следует учитывать при внедрении IME:

  • Предоставьте пользователям возможность задавать параметры непосредственно из пользовательского интерфейса IME.
  • Предоставьте пользователям возможность переключаться на другой IME непосредственно из пользовательского интерфейса метода ввода, поскольку на устройстве может быть установлено несколько IME.
  • Быстро выводит пользовательский интерфейс IME. Предварительно загружает или загружает по требованию любые большие ресурсы, чтобы пользователи видели IME, как только нажимают на текстовое поле. Кэширует ресурсы и представления для последующих вызовов метода ввода.
  • Освобождайте большие объемы памяти сразу после того, как окно метода ввода скрыто, чтобы приложения имели достаточно памяти для работы. Используйте отложенное сообщение для освобождения ресурсов, если IME скрыто на несколько секунд.
  • Убедитесь, что пользователи могут вводить как можно больше символов для языка или локали, связанных с IME. Пользователи могут использовать знаки препинания в паролях или именах пользователей, поэтому ваш IME должен предоставлять много разных символов, чтобы пользователи могли вводить пароль и получать доступ к устройству.