建立輸入法

輸入法編輯器 (IME) 是一種使用者控制項,可讓使用者輸入文字。Android 提供可擴充的輸入法架構,可讓應用程式為使用者提供其他輸入法,例如螢幕小鍵盤或語音輸入。安裝輸入法編輯器後,使用者可以從系統設定中選取所需輸入法編輯器,並在整個系統中使用該輸入法編輯器。一次只能啟用一個 IME。

如要在 Android 系統中新增輸入法編輯器,請建立 Android 應用程式,並納入延伸 InputMethodService 的類別。此外,您通常會建立將選項傳送到輸入法編輯器服務的「設定」活動。您也可以定義顯示在系統設定中的設定使用者介面。

本頁面涵蓋以下主題:

如果您從未使用過輸入法編輯器,請先閱讀簡介文章:螢幕畫面輸入法

輸入法編輯器生命週期

下圖說明輸入法編輯器的生命週期:

顯示輸入法編輯器生命週期的圖片。
圖 1. 輸入法編輯器的生命週期。

以下各節說明如何實作與遵循這個生命週期的輸入法編輯器關聯的使用者介面和程式碼。

在資訊清單中宣告輸入法編輯器元件

在 Android 系統中,輸入法編輯器是內含特殊輸入法編輯器服務的 Android 應用程式。應用程式的資訊清單檔案必須宣告服務、要求必要權限、提供與 action.view.InputMethod 動作相符的意圖篩選器,並提供定義輸入法編輯器特性的中繼資料。此外,如要提供設定介面,讓使用者修改輸入法編輯器的行為,您可以定義「系統設定」中啟動的「設定」活動。

下列程式碼片段會宣告輸入法編輯器服務。該片段會要求 BIND_INPUT_METHOD 權限,允許服務將輸入法編輯器連結至系統、設定符合 android.view.InputMethod 動作的意圖篩選器,並定義輸入法編輯器的中繼資料:

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

下一段程式碼片段會宣告輸入法編輯器的設定活動。該片段具有 ACTION_MAIN 的意圖篩選器,代表此活動是輸入法編輯器應用程式的主要進入點:

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

您也可以直接透過 UI 存取輸入法編輯器設定。

輸入法 API

輸入法編輯器適用的類別位於 android.inputmethodserviceandroid.view.inputmethod 套件中。KeyEvent 類別對於處理鍵盤半形字元至關重要。

輸入法編輯器的中央部分是服務元件,擴充了 InputMethodService 的類別。除了實作正常服務生命週期之外,這個類別還提供回呼,用於提供輸入法編輯器的使用者介面、處理使用者輸入內容,並將文字傳送至目前聚焦欄位。根據預設,InputMethodService 類別提供大部分的實作方式,用於管理輸入法編輯器的狀態和瀏覽權限,並與目前的輸入欄位通訊。

下列類別也很重要:

BaseInputConnection
定義通訊管道,從 InputMethod 傳回到接收其輸入內容的應用程式。可用來讀取遊標周圍的文字、將文字傳送至文字方塊,並將原始金鑰事件傳送至應用程式。應用程式必須擴充這個類別,而不是實作基本介面 InputConnection
KeyboardView
View 的擴充功能,會轉譯鍵盤並回應使用者輸入事件。鍵盤配置是由 Keyboard 的例項指定,您可以在 XML 檔案中定義。

設計輸入法使用者介面

輸入法編輯器有兩個主要視覺元素:輸入檢視畫面和 候選項目檢視畫面。您只需實作與您正在設計的輸入法相關聯的元素。

輸入檢視畫面

輸入檢視畫面是一種使用者介面,可讓使用者以按鍵、手寫或手勢的形式輸入文字。初次顯示輸入法編輯器時,系統會呼叫 onCreateInputView() 回呼。實作此方法時,您會建立想在輸入法編輯器視窗中顯示的版面配置,並將版面配置傳回系統。以下程式碼片段顯示實作 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;
}

在這個範例中,MyKeyboardViewKeyboardView 的自訂實作例項,用於轉譯 Keyboard

待選項目檢視畫面

候選項目檢視畫面是使用者介面,輸入法編輯器可顯示潛在字詞更正或供使用者選擇的建議。在輸入法編輯器生命週期中,當系統準備好顯示候選項目檢視畫面時,系統會呼叫 onCreateCandidatesView()。實作此方法時,會傳回顯示字詞建議的版面配置;如果您不想顯示任何內容,則會傳回空值。空值回應是預設行為,所以如果您沒有提供建議,就不必實作這個動作。

使用者介面設計注意事項

本節說明關於輸入法編輯器的使用者介面設計注意事項。

處理多種螢幕大小

輸入法編輯器的使用者介面必須能夠依據不同螢幕大小縮放,而且必須同時處理橫向和直向瀏覽模式。在非全螢幕輸入法編輯器模式中,應用程式應保留足夠空間來顯示文字欄位和任何相關的背景資訊,因此輸入法編輯器佔用的畫面不超過一半。在全螢幕輸入法編輯器模式下,這不會造成任何問題。

處理不同的輸入類型

Android 文字欄位可讓您設定特定輸入類型,例如任意形式文字、數字、網址、電子郵件地址和搜尋字串。實作新的輸入法編輯器時,請偵測每個欄位的輸入類型,並為欄位提供適當的介面。不過,您不一定要設定輸入法編輯器,以檢查使用者是否為輸入類型輸入了有效文字。這是擁有文字欄位的應用程式應負的責任。

舉例來說,以下是拉丁輸入法編輯器提供的 Android 平台文字輸入介面:

圖片:顯示拉丁輸入法編輯器的文字輸入介面
圖 2. 拉丁輸入法編輯器文字輸入。

以下是拉丁輸入法編輯器為 Android 平台數字輸入提供的介面:

圖片:拉丁輸入法編輯器上的數字輸入介面
圖 3. 拉丁輸入法編輯器數字輸入。

輸入欄位收到聚焦且輸入法編輯器開始時,系統會呼叫 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 所示,拉丁文輸入法編輯器會針對這類型別的欄位顯示數字鍵。
TYPE_CLASS_DATETIME
輸入日期和時間的文字欄位。
TYPE_CLASS_PHONE
輸入電話號碼的文字欄位。
TYPE_CLASS_TEXT
輸入任何支援半形字元的文字欄位。

如需這些常數的詳細說明,請參閱 InputType 的參考說明文件。

inputType 欄位可包含其他位元,用於表示文字欄位類型的變化版本,例如:

TYPE_TEXT_VARIATION_PASSWORD
輸入密碼的 TYPE_CLASS_TEXT 變化版本。輸入法會顯示 dingbats,而非實際文字。
TYPE_TEXT_VARIATION_URI
用於輸入網址和其他統一資源識別碼 (URI) 的 TYPE_CLASS_TEXT 變化版本。
TYPE_TEXT_FLAG_AUTO_COMPLETE
TYPE_CLASS_TEXT 的變化版本,用於輸入應用程式從字典、搜尋或其他工具自動完成的文字。

測試這些變化版本時,請記得以適當的常數遮蓋 inputType。您可以在 InputType 的參考說明文件中查看可用的遮蓋常數。

傳送簡訊至應用程式

當使用者透過輸入法編輯器輸入文字時,您可以傳送個別金鑰事件,或在應用程式的文字欄位中編輯遊標周圍的文字,將文字傳送至應用程式。無論是哪一種情況,您都必須使用 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);

支援在提交前編寫文字

如果輸入法編輯器會預測文字,或需要完成多個步驟來打造字符或字詞,您可以在文字欄位中顯示進度,直到使用者提交字詞為止,接著您可以將部分撰寫替換為完整文字內容。您可以將文字傳遞至 setComposingText() 時加上 span,藉此提供特殊的處理方式。

以下程式碼片段說明如何在文字欄位中顯示進度:

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() 方法。

建立輸入法編輯器子類型

子類型可讓輸入法編輯器顯示輸入法編輯器支援的多個輸入模式和語言。子類型可代表下列項目:

  • 語言代碼,例如 en_US 或 fr_FR
  • 輸入模式,例如語音、鍵盤或手寫
  • 其他特定於輸入法編輯器的輸入樣式、表單或屬性,例如 10 鍵或 QWERTY 鍵盤版面配置

模式可以是任何文字,例如「鍵盤」或「語音」。而子類型也可以公開顯示這些組合。

子類型資訊用於通知列和輸入法編輯器設定提供的輸入法編輯器切換器對話方塊。資訊也允許該架構直接顯示特定輸入法編輯器子類型。建構輸入法編輯器時,請使用子類型設施,以便使用者識別和切換不同的輸入法編輯器語言和模式。

使用 <subtype> 元素在輸入法的 XML 資源檔案中定義子類型。以下程式碼片段定義包含兩種子類型的輸入法編輯器:美國英文語言代碼適用的鍵盤子類型,以及法國法文語言代碼的另一個鍵盤子類型:

<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)」(英文 [美國])。

從通知列中選擇輸入法編輯器子類型

Android 系統可以管理所有輸入法編輯器提供的所有子類型。系統會將輸入法編輯器子類型視為其所屬輸入法編輯器的模式。使用者可以從通知列或「設定」應用程式前往可用的輸入法編輯器子類型的選單,如下圖所示:

圖片:顯示「語言與輸入設定」系統選單
圖 4. 「語言與輸入設定」系統選單。

從「系統設定」中選擇輸入法編輯器子類型

使用者也可以在系統設定的「語言和輸入」設定面板中控制子類型的使用方式:

顯示「Languages」選單的圖片
圖 5. Languages 系統選單

切換輸入法編輯器子類型

您可以在鍵盤上提供切換鍵 (例如地球形狀的語言圖示),讓使用者輕鬆切換多種輸入法編輯器子類型。這麼做可提升鍵盤的可用性,並方便使用者操作。如要啟用這項切換功能,請按照下列步驟操作:

  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. 如果這個方法傳回「是」,顯示切換鍵。
  4. 使用者輕觸切換鍵時,請呼叫 switchToNextInputMethod(),並傳遞「否」。值為「否」能讓系統平等處理所有子類型,無論其屬於哪個輸入法編輯器。指定「是」時,要求系統循環顯示目前輸入法編輯器中的子類型。

一般輸入法編輯器注意事項

實作輸入法編輯器時,請考量以下其他事項:

  • 為使用者提供直接透過輸入法編輯器使用者介面設定選項的方法。
  • 由於裝置上可能會安裝多個輸入法編輯器,因此請提供方法,讓使用者直接從輸入法使用者介面切換至其他輸入法編輯器。
  • 快速開啟輸入法編輯器的 UI。視需求預先載入或載入任何大型資源,方便使用者在輕觸文字欄位後查看輸入法編輯器。快取資源和檢視畫面,以供輸入法的日後叫用。
  • 在隱藏輸入視窗後立即釋出大量記憶體配置,以便讓應用程式有足夠的記憶體可以執行。如果輸入法編輯器隱藏幾秒鐘,請使用延遲訊息釋出資源。
  • 請確保使用者能夠使用與輸入法編輯器相關聯的語言或語言代碼,盡可能輸入更多半形字元。使用者可能會在密碼或使用者名稱中使用標點符號,因此輸入法編輯器必須提供許多不同的半形字元,讓使用者輸入密碼才能存取裝置。