创建输入法

输入法 (IME) 是一种可让用户输入文本的用户控件。Android 提供了一种 一种可扩展的输入法框架,可让应用为用户提供备选输入法, 例如屏幕键盘或语音输入。安装 IME 后,用户可以从 并将其应用于整个系统。一次只能启用一个 IME。

要向 Android 系统添加 IME,请创建一个 Android 应用,其中包含一个 扩展 InputMethodService。 此外,您通常需要创建“设置”此 activity 会将选项传递给 IME 服务。您 还可以定义一个设置界面,该界面会作为系统设置的一部分显示。

本页面包含以下主题:

如果您未使用过 IME,请阅读介绍性文章 屏幕输入法

<ph type="x-smartling-placeholder">

IME 生命周期

下图描述了 IME 的生命周期:

显示 IME 生命周期的图片。
图 1. IME 的生命周期。

下面几部分介绍了如何实现与以下 IME 相关联的界面和代码: 遵循此生命周期。

在清单中声明 IME 组件

在 Android 系统中,IME 是包含一项特殊 IME 服务的 Android 应用。通过 应用的清单文件必须声明相应服务、请求必要的权限、提供 与操作 action.view.InputMethod 匹配并提供元数据的 intent 过滤器 ,用于定义 IME 的特征。此外,为了提供设置界面, 用户修改 IME 的行为,您可以定义一个“设置”可从以下位置启动的 activity 系统设置。

以下代码段声明了一项 IME 服务。它会请求 BIND_INPUT_METHOD 让该服务将 IME 连接到系统,设置一个与操作匹配的 intent 过滤器 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 的设置 activity。它有一个 ACTION_MAIN 表示此 Activity 是 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 界面访问 IME 设置。

输入法 API

特定于 IME 的类位于 android.inputmethodserviceandroid.view.inputmethod 软件包KeyEvent 类 对处理键盘字符非常重要。

IME 的核心部分是一个服务组件,它是一个扩展 InputMethodService。除了实现正常的服务生命周期之外, 类具有回调,用于提供 IME 的界面、处理用户输入以及将文本传递给 具有焦点的字段。默认情况下,InputMethodService 类提供大部分 用于管理 IME 的状态和可见性以及与当前通信的实现 输入字段。

以下类也很重要:

BaseInputConnection
定义从 InputMethod 返回给正在接收输入的应用。您可以使用该类读取光标周围的文本,将文本提交至文本框,然后将原始按键事件发送到应用。应用必须扩展此类,而不是实现基接口 InputConnection
KeyboardView
View 的扩展, 呈现键盘并响应用户输入事件。键盘布局由 实例 Keyboard, 您可在 XML 文件中定义此名称

设计输入法界面

IME 有两个主要的视觉元素:输入视图和 候选人视图。您只需要实施 输入的方式

输入视图

输入视图是指用户以点击按键、手写或 手势。当 IME 首次显示时,系统会调用 onCreateInputView() 回调。在此方法的实现中,创建您想要在 IME 中显示的布局 并将布局返回系统。以下代码段展示了使用 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;
}

在此示例中,MyKeyboardView 是以下自定义实现的实例: 用于渲染 KeyboardKeyboardView

候选视图

候选视图是 IME 显示可能的字词更正或建议的界面 供用户选择在 IME 生命周期中,系统调用 onCreateCandidatesView() 。在此方法的实现中,返回一个 显示字词建议的布局;如果您不想显示任何内容,则返回 null。null 是默认行为,因此,如果您没有提供 建议。

界面设计注意事项

本部分介绍了一些 IME 界面设计注意事项。

处理多种屏幕尺寸

IME 界面必须能够针对不同的屏幕尺寸进行缩放,并处理两种横向模式 和纵向模式在非全屏 IME 模式下,留出足够的空间供应用执行 显示文本字段和任何相关上下文,确保用户所占的屏幕空间不超过一半 IME。在全屏 IME 模式下,不存在此问题。

处理不同的输入类型

Android 文本字段可让您设置特定的输入类型,例如自由格式文本、数字、网址 电子邮件地址和搜索字符串。实现新的 IME 时,检测每个 IME 的输入类型 字段并为其提供相应的接口。不过,您无需设置 IME 检查用户是否为输入类型输入了有效的文本。其职责是 以及拥有该文本字段的应用

例如,以下是拉丁语 IME 为 Android 平台文本提供的接口 输入:

显示拉丁语 IME 上的文本输入的图片
图 2. 拉丁语 IME 文本输入。

这里是拉丁语 IME 为 Android 平台提供的接口 数字输入:

一张图片,显示拉丁语 IME 中的数字输入
图 3. 拉丁语 IME 数字输入。

当某个输入字段获得焦点并且您的 IME 启动时,系统会调用 onStartInputView(), 传入 EditorInfo 个对象 ,其中包含有关输入类型和其他文本字段属性的详情。在此对象中, 该 inputType 字段包含文本字段的输入类型。

inputType 字段是一个 int,其中包含各种 输入类型设置。如需针对文本字段的输入类型对其进行测试,请使用常量遮盖它 TYPE_MASK_CLASS, 如下所示:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

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 的变体,用于输入网址和其他统一资源 标识符 (URI)。
TYPE_TEXT_FLAG_AUTO_COMPLETE
TYPE_CLASS_TEXT 的变体,用于输入应用 通过字典、搜索或其他工具提供的自动补全功能。

在测试这些变体时,使用适当的常量遮盖 inputType。通过 InputType 的参考文档中列出了可用的遮盖常量。

<ph type="x-smartling-placeholder">

向应用发送文本

当用户使用您的 IME 输入文本时,您可以通过向应用发送单个 或编辑应用程序文本字段中光标周围的文本。无论是哪种情况 使用 InputConnection 实例传递文本。要获取此实例,请调用 InputMethodService.getCurrentInputConnection()

修改光标周围的文本

处理现有文本的编辑时, BaseInputConnection 如下:

getTextBeforeCursor()
返回 CharSequence 包含当前光标位置之前所请求的字符数。
getTextAfterCursor()
返回 CharSequence,其中包含 当前光标位置。
deleteSurroundingText()
删除当前光标位置前后指定数量的字符。
commitText()
CharSequence 提交到文本字段并设置新的光标位置。

例如,以下代码段展示了如何替换 文本“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);

支持在提交之前撰写文本

如果您的 IME 可以预测文本,或者需要执行多个步骤来撰写字形或字词,您可以 输入文字的进度,直到用户提交单词,然后您就可以将 使用完成的文本撰写内容。您可以通过向文本添加 span setComposingText()

以下代码段演示了如何在文本字段中显示进度:

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

拦截硬件按键事件

即使输入法窗口没有明确的焦点,它也会接收硬件按键事件 可以先使用它们,或者将它们转发给应用例如,您可能希望 使用方向键在您的界面中导航,以便在撰写期间选择候选词。 您可能还想按下返回键来关闭来自该输入法的所有对话框 窗口。

如需拦截硬件按键,请替换 onKeyDown()onKeyUp()

针对您不想自行处理的按键调用 super() 方法。

创建 IME 子类型

通过子类型,IME 可以显示多种受支持的输入法和语言。子类型可以 表示以下内容:

  • 语言区域,例如 en_US 或 fr_FR
  • 输入模式,例如语音输入、键盘输入或手写输入
  • IME 特有的其他输入样式、表单或属性,例如 10 键或 QWERTY 键盘 键盘布局

模式可以是任何文字,例如“keyboard”或“语音”。子类型还可以显示 其中之一。

子类型信息用于从通知栏中提供的 IME 切换器对话框 和 IME 设置通过这些信息,框架还可以调出 IME 的特定子类型 。在构建 IME 时,请使用子类型工具,因为它可以帮助用户识别和 在不同的 IME 语言和模式之间切换。

使用 <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" />

第二个代码段是 IME 的 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 子类型之间切换

您可以提供切换键(例如 地球形状的语言图标。这可以提高键盘的易用性 。如需启用此切换功能,请执行以下步骤:

  1. 在输入法的 XML 资源文件中声明 supportsSwitchingToNextInputMethod = "true"。您的声明必须类似于以下代码段:
    <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 相关联的 ID。用户可能会在密码或用户名中使用标点符号,因此您的 IME 必须提供多种不同的字符,以便用户输入密码和访问 设备。