自定義Android鍵盤

flueky發表於2018-04-25

前言

前段時間改造了公司的安全鍵盤,是基於DialogButton自定義的。也因此藉機瞭解下 Android 平臺提供的自定義鍵盤介面。主要有兩個類:KeyboardKeyboardView。很搞笑的是,百度出來自定義Android鍵盤(與自定義Android輸入法不同)的文章千篇一律。

注:這裡講的自定義鍵盤同公司安全鍵盤是兩種實現方式,不存在洩露公司內部技術的問題!!!

不去吐槽別人,樓主秉持只原創和翻譯的作風,輸出這第50篇部落格。相關屬性部分是對照官方文件和Demo實踐翻譯的,若有瑕疵,請見諒。樓主csdn主頁請點選flueky專欄

相關屬性

Keyboard

序號 屬性 型別 描述
1 keyHeight dimension/fractional Key高度,區分精確值(dp、px等)和相對值(%、%p)
2 keyWidth dimension/fractional Key寬度,同上
3 horizontalGap dimension/fractional Key水平間隙,同上
4 verticalGap dimension/fractional Key按鍵間隙(垂直),同上

Row

序號 屬性 型別 描述
1 keyHeight dimension/fractional Key高度,區分精確值(dp、px等)和相對值(%、%p)
2 keyWidth dimension/fractional Key寬度,同上
3 horizontalGap dimension/fractional Key水平間隙,同上
4 verticalGap dimension/fractional Key按鍵間隙(垂直),同上
5 keyboardMode reference 鍵盤型別,如果該行的型別不符合鍵盤的型別,將跳過該行。
6 rowEdgeFlags enum 行邊界標記,top/bottom,鍵盤頂(底)部錨點。

Key

序號 屬性 型別 描述
1 keyHeight dimension/fractional Key高度,區分精確值(dp、px等)和相對值(%、%p)
2 keyWidth dimension/fractional Key寬度,同上
3 horizontalGap dimension/fractional Key水平間隙,同上
4 verticalGap dimension/fractional Key按鍵間隙(垂直),同上
5 codes int Key輸出符號對應的Unicode值,官方還說支援字轉義字串,不明白。
6 iconPreview reference 彈出回顯的icon
7 isModifier boolean 是否功能修飾鍵,如:Alt/Shift
8 isSticky boolean 是否是開關鍵
9 isRepeatable boolean 是否允許重複。true表示長按時重複執行。
10 keyEdgeFlags enum Key邊緣位置標記,left/right,鍵盤左(右)邊錨點。
11 keyIcon reference 替換label顯示在按鍵上的icon。
12 keyLabel reference 顯示在Key上的標籤。
13 keyOutputText string Key按下時輸出的字元或字串。
14 popupCharacters string 小鍵盤顯示的字元,用於顯示Key候選項。
15 popupKeyboard reference 按鍵候選小鍵盤的keyboard佈局

KeyboardView

序號 屬性 型別 描述
1 keyBackground reference 按鍵的影像背景,必須包含多個狀態的drawable
2 verticalCorrection dimension 補充觸控y座標的偏移,用於偏差矯正
3 keyPreviewLayout reference 按鍵按下時預覽框的佈局
4 keyPreviewOffset dimension 按鍵按下時預覽框的偏移。>0 向下,<0 向上。
5 keyPreviewHeight dimension 按鍵按下時預覽框的高度。
6 keyTextSize dimension 按鍵文字大小。
7 keyTextColor color 按鍵文字顏色。
8 labelTextSize dimension 標籤文字大小,keylabel有多個字元且keycodes只有一個值時,該屬性生效。
9 popupLayout reference 按鍵候選小鍵盤的KeyboardView佈局。
10 shadowRadius float 按鍵文字陰影半徑
11 shadowColor color 按鍵文字陰影顏色

自定義鍵盤

佈局

<android.inputmethodservice.KeyboardView
    android:id="@+id/activity_main_keyboard"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#212121"
    android:keyBackground="@drawable/key_bg"
    android:keyTextColor="#dddddd"
    android:keyTextSize="18sp"
    android:labelTextSize="18sp"
    android:paddingBottom="2dp"
    android:paddingTop="2dp" />
複製程式碼

鍵盤容器檢視,Demo中直接放在Activity佈局。KeyboardView可以顯示不同型別的Keyboard。請區分backgroundkeyBackgroundkeyBackground內容如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 此處設定key邊距 -->
    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <selector>
            <!-- 按壓後圖層 -->
            <item android:state_pressed="true">
                <shape>
                    <solid android:color="#565656" />
                    <corners android:radius="5dp" />
                </shape>
            </item>
            <!-- 正常狀態圖層 -->
            <item>
                <shape>
                    <solid android:color="#383838" />
                    <corners android:radius="5dp" />
                </shape>
            </item>
        </selector>
    </item>
</layer-list>
複製程式碼

字母鍵盤佈局

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyHeight="50dp"
    android:keyWidth="10%p">
    <Row android:rowEdgeFlags="top">
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="q" />
        <Key android:keyLabel="w" />
        <Key android:keyLabel="e" />
        <Key android:keyLabel="r" />
        <Key android:keyLabel="t" />
        <Key android:keyLabel="y" />
        <Key android:keyLabel="u" />
        <Key android:keyLabel="i" />
        <Key android:keyLabel="o" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="p" />
    </Row>
    <Row>
        <Key
            android:codes="97"
            android:horizontalGap="5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="a" />
        <Key android:keyLabel="s" />
        <Key android:keyLabel="d" />
        <Key android:keyLabel="f" />
        <Key android:keyLabel="g" />
        <Key android:keyLabel="h" />
        <Key android:keyLabel="j" />
        <Key android:keyLabel="k" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="l" />
    </Row>
    <Row>
        <Key
            android:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyEdgeFlags="left"
            android:keyIcon="@drawable/key_caps_lock_icon"
            android:keyWidth="15%p" />
        <Key android:keyLabel="z" />
        <Key android:keyLabel="x" />
        <Key android:keyLabel="c" />
        <Key android:keyLabel="v" />
        <Key android:keyLabel="b" />
        <Key android:keyLabel="n" />
        <Key android:keyLabel="m" />

        <Key
            android:codes="-5"
            android:isModifier="true"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyIcon="@drawable/key_delete_icon"
            android:keyWidth="15%p" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-11"
            android:keyEdgeFlags="left"
            android:keyLabel="123"
            android:keyWidth="15%p" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyLabel=" "
            android:keyWidth="70%p" />
        <Key
            android:codes="-12"
            android:keyEdgeFlags="right"
            android:keyLabel="#+="
            android:keyWidth="15%p" />
    </Row>
</Keyboard>
複製程式碼

效果圖如下:

自定義Android鍵盤 自定義Android鍵盤

數字鍵盤佈局

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyHeight="50dp"
    android:keyWidth="33.3%p">
    <Row>
        <Key
            android:codes="49"
            android:keyLabel="1" />
        <Key
            android:codes="50"
            android:keyLabel="2" />
        <Key
            android:codes="51"
            android:keyLabel="3" />
    </Row>
    <Row>
        <Key
            android:codes="52"
            android:keyLabel="4" />
        <Key
            android:codes="53"
            android:keyLabel="5" />
        <Key
            android:codes="54"
            android:keyLabel="6" />
    </Row>
    <Row>
        <Key
            android:codes="55"
            android:keyLabel="7" />
        <Key
            android:codes="56"
            android:keyLabel="8" />
        <Key
            android:codes="57"
            android:keyLabel="9" />
    </Row>
    <Row>
        <Key
            android:codes="-10"
            android:keyLabel="ABC" />
        <Key
            android:codes="48"
            android:keyLabel="0" />
        <Key
            android:codes="-12"
            android:keyLabel="#+=" />
    </Row>
</Keyboard>
複製程式碼

效果圖如下:

自定義Android鍵盤
  1. Key之間的間隙不建議使用horizontalGapverticalGap 設定。有興趣可以嘗試下,設定後會出現什麼效果。此處採用drawablepadding屬性。
  2. keyLabel屬性只有一個字元時,當做輸入鍵,keyLabel有多個字元時,如果codes也有多個值,仍然當做輸入鍵,keyTextSize 值有效;只有一個值時當做功能鍵。labelTextSize值有效。
  3. codes 屬性可以省略,預設使用keyLabel字元的Unicode值。功能鍵等其他自定義按鍵的 key code 建議設定為負數。
  4. codes有多個值時,單擊取第一個,雙擊取第二個,三連擊取第三個。通常建議該屬性值不要超過3個。多個值用逗號分隔。

邏輯

final Keyboard pinyin26KB = new Keyboard(this, R.xml.pinyin_26);// 字母鍵盤
final Keyboard numberKB = new Keyboard(this, R.xml.number); // 數字鍵盤

keyboardView.setKeyboard(pinyin26KB); // 設定預設顯示字元鍵盤
keyboardView.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {

   // 按下 key 時執行
   @Override
   public void onPress(int primaryCode) {
       Log.d(TAG, "onPress: "+primaryCode);
   }

   // 釋放 key 時執行
   @Override
   public void onRelease(int primaryCode) {
       Log.d(TAG, "onRelease: "+primaryCode);
   }

   // 點選 key 時執行
   @Override
   public void onKey(int primaryCode, int[] keyCodes) {
       Editable editable = edtInput.getText();
       int start = edtInput.getSelectionStart();
       switch (primaryCode) {
           case Keyboard.KEYCODE_SHIFT:// 設定shift狀態然後重新整理頁面
               pinyin26KB.setShifted(!pinyin26KB.isShifted());
               keyboardView.invalidateAllKeys();
               break;
           case Keyboard.KEYCODE_DELETE:// 點選刪除鍵,長按連續刪除
               if (editable != null && editable.length() > 0 && start > 0) {
                   editable.delete(start - 1, start);
               }
               break;
           case -10:// 自定義code,切換到拼音鍵盤
               keyboardView.setKeyboard(pinyin26KB);
               break;
           case -11:// 自定義code,切換到字母鍵盤
               keyboardView.setKeyboard(numberKB);
               break;
           case -12:// 自定義code
               // 切換到符號鍵盤,待實現
               break;
           default:// 數值code
               if (primaryCode >= 97 && primaryCode <= 97 + 26) {// 按下字母鍵
                   editable.insert(start, pinyin26KB.isShifted() ? Character.toString((char) (primaryCode - 32)) : Character.toString((char) (primaryCode)));
               } else {// 其他code值,轉字元在輸入框中顯示
                   editable.insert(start, Character.toString((char) (primaryCode)));
               }
               break;
       }
   }

   // 設定了 keyOutputText 屬性後執行。
   @Override
   public void onText(CharSequence text) {
       Log.d(TAG, "onText: "+text);
   }
});
複製程式碼

已經定義的功能鍵code值,如下:

   public static final int KEYCODE_SHIFT = -1;
   public static final int KEYCODE_MODE_CHANGE = -2;
   public static final int KEYCODE_CANCEL = -3;
   public static final int KEYCODE_DONE = -4;
   public static final int KEYCODE_DELETE = -5;
   public static final int KEYCODE_ALT = -6;
複製程式碼
  1. Shift鍵需要設定 isStickyisModifier 值為truecodes值為-1。
  2. Delete鍵需要設定isRepeatableisModifier 值為truecodes值為-5。
  3. 切換鍵盤的功能鍵需要自定義上述中未用到的code值,在onKey方法中做好對應的處理。

回顯

keyboardView.setPreviewEnabled(true);
複製程式碼

開啟回顯,預設是true。

android:keyPreviewLayout="@layout/preview"
android:keyPreviewHeight="50dp"
android:keyPreviewOffset="-20dp"
複製程式碼

在鍵盤容器中宣告以上屬性。

自定義Android鍵盤

備選小鍵盤

pupop_layout.xml 備選小鍵盤容器:

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@android:id/keyboardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#212121"
    android:keyBackground="@drawable/popup_bg"
    android:keyPreviewHeight="60dp"
    android:keyPreviewLayout="@layout/preview"
    android:keyPreviewOffset="-10dp"
    android:keyTextColor="#dddddd"
    android:keyTextSize="18sp"
    android:labelTextSize="18sp" />
複製程式碼

pupop.xml 備選小鍵盤檢視:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/popup_bg"
    android:keyHeight="50dp">

    <Row>
        <Key android:codes="97" />

        <Key android:codes="98" />

        <Key android:codes="99" />
    </Row>

</Keyboard>
複製程式碼

w鍵新增備選功能:

<Key
    android:keyLabel="w"
    android:popupCharacters="123"
    android:popupKeyboard="@layout/pupop" />
複製程式碼

在鍵盤容器中,指定備選小鍵盤佈局:

android:popupLayout="@layout/pupop_layout"
複製程式碼

如果只宣告瞭popupCharacters,沒有宣告popupLayoutpopupKeyboard,將會使用預設佈局。只宣告popupLayout沒宣告popupKeyboardpopupLayout無效。

自定義Android鍵盤

相關文章