建立輸入法

Stay organized with collections Save and categorize content based on your preferences.

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

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

本指南涵蓋下列項目:

  • 輸入法編輯器生命週期
  • 在應用程式資訊清單中宣告輸入法編輯器元件
  • 輸入法編輯器 API
  • 設計輸入法編輯器使用者介面
  • 從輸入法編輯器將文字傳送至應用程式
  • 使用輸入法編輯器子類型

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

輸入法編輯器生命週期

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

圖 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. 拉丁輸入法編輯器輸入類型。

輸入欄位收到聚焦且輸入法編輯器開始時,系統會呼叫 onStartInputView(),並傳入 EditorInfo 物件,其中包含輸入類型與文字欄位其他屬性的詳細資料。在這個物件中,inputType 欄位包含文字欄位的輸入類型。

inputType 欄位是 int,其中包含多種輸入類型設定的位元模式。如要測試文字欄位的輸入類型,請使用常數 TYPE_MASK_CLASS 進行遮蓋,如下所示:

Kotlin

inputType and InputType.TYPE_MASK_CLASS

Java

inputType & InputType.TYPE_MASK_CLASS

輸入類型位元模式可以是下列任一值,包括:

TYPE_CLASS_NUMBER
輸入數字的文字欄位。如前一張螢幕截圖所示,拉丁文輸入法編輯器顯示此類型字段的數字鍵。
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);

以下螢幕截圖顯示了對使用者的顯示情況:

圖 3. 發布前先編寫文字。

攔截硬體金鑰事件

儘管輸入方式視窗沒有明確的聚焦,但仍會先收到硬體金鑰事件,再選擇或取用這些金鑰給應用程式。例如,您可能希望使用方向鍵在使用者介面中瀏覽,以便在撰寫過程中選取待選選項。您也可以擷取返回鍵,關閉所有來自輸入法的彈出式視窗。

如要攔截硬體金鑰,請覆寫 onKeyDown()onKeyUp()

針對不想要自行處理的金鑰,請務必呼叫 super() 方法。

建立輸入法編輯器子類型

子類型允許輸入法編輯器顯示輸入法編輯器支援的多個輸入模式和語言。一個子類型可代表:

  • 語言代碼,例如美國英文或法國法文。
  • 輸入模式,例如語音、鍵盤或手寫。
  • 其他特定於輸入法編輯器的輸入樣式、表單或屬性,例如 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:imeSubtypeLanguage="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:imeSubtypeLanguage="fr_FR"
            android:imeSubtypeMode="keyboard"
            android:imeSubtypeExtraValue="foobar=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. 從通知列中選擇輸入法編輯器子類型。

圖 5. 您可以在「系統設定」中設定子類型偏好設定。

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

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

圖 6. 為輸入法編輯器選擇語言。

切換輸入法編輯器子類型

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

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

注意:在 Android 5.0 (API 級別 21) 之前,switchToNextInputMethod() 並不知道 supportsSwitchingToNextInputMethod 屬性。如果使用者切換至沒有切換金鑰的輸入法編輯器,使用者可能會卡在輸入法編輯器中,無法輕易轉出。

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

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

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