前言
前段时间改造了公司的安全键盘是基于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。<br/>Delete
键需要设置isRepeatable
和isModifier
值为true
codes
值为-5。<br/>切换键盘的功能键需要自定义上述中未用到的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
无效。