前言
前段時間改造了公司的安全鍵盤,是基於Dialog
和Button
自定義的。也因此藉機瞭解下 Android 平臺提供的自定義鍵盤介面。主要有兩個類:Keyboard
和KeyboardView
。很搞笑的是,百度出來自定義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。請區分
background
和keyBackground
。keyBackground
內容如下:
<?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>
複製程式碼
效果圖如下:
數字鍵盤佈局
<?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>
複製程式碼
效果圖如下:
- Key之間的間隙不建議使用
horizontalGap
和verticalGap
設定。有興趣可以嘗試下,設定後會出現什麼效果。此處採用drawable
的padding
屬性。 keyLabel
屬性只有一個字元時,當做輸入鍵,keyLabel
有多個字元時,如果codes
也有多個值,仍然當做輸入鍵,keyTextSize
值有效;只有一個值時當做功能鍵。labelTextSize
值有效。codes
屬性可以省略,預設使用keyLabel字元的Unicode值。功能鍵等其他自定義按鍵的 key code 建議設定為負數。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;
複製程式碼
Shift
鍵需要設定isSticky
和isModifier
值為true
,codes
值為-1。Delete
鍵需要設定isRepeatable
和isModifier
值為true
,codes
值為-5。- 切換鍵盤的功能鍵需要自定義上述中未用到的code值,在
onKey
方法中做好對應的處理。
回顯
keyboardView.setPreviewEnabled(true);
複製程式碼
開啟回顯,預設是true。
android:keyPreviewLayout="@layout/preview"
android:keyPreviewHeight="50dp"
android:keyPreviewOffset="-20dp"
複製程式碼
在鍵盤容器中宣告以上屬性。
備選小鍵盤
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
,沒有宣告popupLayout
和popupKeyboard
,將會使用預設佈局。只宣告popupLayout
沒宣告popupKeyboard
,popupLayout
無效。