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

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

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

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

Если вы еще не работали с 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:

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

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

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

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

Этот параметр приводит к тому, что отображаемое имя подтипа соответствует настройке языкового стандарта. Например, в любом английском языковом стандарте отображаемое имя — «Английский (США)».

Выберите подтипы 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 должен предоставлять множество разных символов, чтобы пользователи могли вводить пароль и получать доступ к устройству.