建立輸入法

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

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

本頁面會說明下列主題:

如果您尚未使用 IME,請先參閱簡介文章「畫面上的輸入法」。

輸入法編輯器生命週期

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

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

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

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

在 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 檔案中定義。

設計輸入法使用者介面

IME 有兩個主要的視覺元素:「input」檢視畫面和「候選」檢視畫面。您只需實作與您正在設計的輸入方法相關的元素。

輸入檢視畫面

輸入檢視畫面是一種使用者介面,可讓使用者以鍵盤按鍵、手寫或手勢的形式輸入文字。初次顯示輸入法編輯器時,系統會呼叫 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 文字欄位可讓您設定特定輸入類型,例如任意形式文字、數字、網址、電子郵件地址和搜尋字串。實作新的輸入法編輯器時,請偵測每個欄位的輸入類型,並為欄位提供適當的介面。不過,您並不需要設定輸入法編輯器,檢查使用者輸入的輸入類型是否有效文字。這項責任是擁有文字欄位的應用程式負責的工作。

舉例來說,以下是拉丁 IME 為 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);

支援在提交前撰寫文字

如果 IME 會預測文字,或需要完成多個步驟才能組合字符或字詞,您可以在文字欄位中顯示進度,直到使用者提交字詞為止,接著您可以將部分組成取代為完整文字。您可以將文字傳遞至 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);

攔截硬體金鑰事件

雖然輸入法視窗沒有明確的焦點,但會先接收硬體按鍵事件,再加以取用或轉送至應用程式。例如,您可能想要使用方向鍵在 UI 中瀏覽,以便在組合期間選擇候選鍵。建議您擷取返回鍵,關閉來自輸入法視窗的任何對話方塊。

如要攔截硬體金鑰,請覆寫 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 檔案。輸入法 UI 定義用於設定子類型標籤的字串資源 label_subtype_generic 定義如下:

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

這項設定會使子類型的顯示名稱與地區設定相符。例如,任何英文語言代碼的顯示名稱都是「English (United States)」(英文 (美國))。

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

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

顯示「語言與輸入系統」選單的圖片
圖 4. 「Languages & input」(語言與輸入) 系統選單。

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

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

顯示語言選項選單的圖片
圖 5. 「語言」系統選單

切換輸入法編輯器子類型

您可以提供切換鍵 (例如鍵盤上的地球形狀語言圖示),讓使用者輕鬆切換輸入法編輯器子類型。這會讓鍵盤使用起來更方便,也更方便使用者。如要啟用這項切換,請按照下列步驟操作:

  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() 並傳遞 false。值為「否」能讓系統平等處理所有子類型,無論其屬於哪個輸入法編輯器。指定「是」時,要求系統循環顯示目前輸入法編輯器中的子類型。

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

實作輸入法編輯器時,還需要考量以下幾點:

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