现在很多场景需要使用自定义键盘,比如银行app的乱序密码键盘。现在做个demo,用最快的速度、最少的代码做出一个数字键盘,有基本的操作按键,效果如下图:
自定义键盘的实现,需要用到系统Keyboard和KeybaordView两个类。
Keyboard
Keybard类可以加载一个描述键盘按键的xml文件,demo里的按键布局如下:
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1dp"
android:verticalGap="1dp"
android:keyWidth="20%p"
android:keyHeight="50dp">
<Row>
<Key android:codes="-10" android:keyLabel="清空"
android:keyEdgeFlags="left"/>
<Key android:codes="49" android:keyLabel="1"/>
<Key android:codes="50" android:keyLabel="2"/>
<Key android:codes="51" android:keyLabel="3"/>
<Key android:codes="-3" android:keyLabel="收起"
android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="-11" android:keyLabel="上一项"
android:keyEdgeFlags="left"
android:keyHeight="100.5dp"/>
<Key android:codes="52" android:keyLabel="4"/>
<Key android:codes="53" android:keyLabel="5"/>
<Key android:codes="54" android:keyLabel="6"/>
<Key android:codes="-12" android:keyLabel="下一项"
android:keyEdgeFlags="right"
android:keyHeight="100.5dp"/>
</Row>
<Row>
<Key android:codes="-99" android:keyHeight="0dp" android:keyEdgeFlags="left"/>
<Key android:codes="55" android:keyLabel="7"/>
<Key android:codes="56" android:keyLabel="8"/>
<Key android:codes="57" android:keyLabel="9"/>
<Key android:codes="-99" android:keyHeight="0dp" android:keyEdgeFlags="right"/>
</Row>
<Row>
<Key android:codes="-99" android:keyEdgeFlags="left"/>
<Key android:codes="45" android:keyLabel="-"/>
<Key android:codes="48" android:keyLabel="0"/>
<Key android:codes="46" android:keyLabel="."/>
<Key android:codes="-5" android:keyLabel="删除"
android:keyEdgeFlags="right"
android:isRepeatable="true"/>
</Row>
</Keyboard>
要注意的地方是:
- 键盘布局放在/res/xml
- 输出字符按键的android:codes需要是对应的ASCII码
- 有预定义常用操作,比如取消、完成、删除,可以直接用
比较折腾的是不知道如何让按键跨行跨列,文档里没有找到任何span方法。跨列容易解决,单独修改keyWidth就可以。跨行的话,现在的实现是让上一行key的height双倍,下一行的height为0,最终实现demo的效果,求更好的方法。
KeyboardView
KeyboardView处理了键盘的绘制、触摸、滑动等动作,加进Activity的布局里。
<android.inputmethodservice.KeyboardView
android:id="@+id/custom_keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="@color/lightgray"
android:keyBackground="@drawable/btn_keyboard_key"
android:keyTextColor="@color/black"
android:keyTextSize="20dp"
android:paddingTop="1px"
android:shadowRadius="0"
android:visibility="gone"/>
具体属性参考官方文档,到这里,自定义键盘的ui已经定义好,下面看怎样跑起来。
键盘初始化
private void initKeyboard() {
Keyboard keyboard = new Keyboard(this, R.xml.number_input_keyboard);
mBinding.customKeyboard.setKeyboard(keyboard);
mBinding.customKeyboard.setEnabled(true);
mBinding.customKeyboard.setPreviewEnabled(false);
mBinding.customKeyboard.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
doCustomKeyboardKey(primaryCode, keyCodes);
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
});
}
Keyboard和KeyboardView的初始化很简单,最重要的是实现OnKeyboardActionListener,提供了多个动作的回调,demo简单实现按键点击的处理。
private void doCustomKeyboardKey(int primaryCode, int[] keyCodes) {
Editable editable;
int selectionStart;
if (mBinding.et1.isFocused()) {
editable = mBinding.et1.getText();
selectionStart = mBinding.et1.getSelectionStart();
} else {
editable = mBinding.et2.getText();
selectionStart = mBinding.et2.getSelectionStart();
}
if (primaryCode == Keyboard.KEYCODE_CANCEL) {
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {
if (editable.length() > 0 && selectionStart > 0) {
editable.delete(selectionStart - 1, selectionStart);
}
} else if (primaryCode == -10) {
if (editable.length() > 0) {
editable.clear();
}
} else if (primaryCode == -11) {
mBinding.et1.requestFocus();
} else if (primaryCode == -12) {
mBinding.et2.requestFocus();
} else if (primaryCode == -99) {
//do nothing
} else {
editable.insert(selectionStart, Character.toString((char) primaryCode));
}
}
根据xml文件里预定好的primaryCode,根据实际情况处理各个按键的效果。
自定义EditText
使用自定义键盘的EditText需要增加处理系统键盘,最简单的方法就是直接隐藏。
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
requestFocus();
requestFocusFromTouch();
hideSysInput();
return true;
}
自定义键盘的打开
mBinding.et1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBinding.customKeyboard.setVisibility(View.VISIBLE);
}
});
EditText增加监听onClick事件,直接让键盘显示。为什么不用OnFocusChangeListener呢,因为主动收起键盘,EditText的焦点没有改变,只有onClick才能再触发键盘打开。
几段代码就实现了一个自定义键盘,挺简单的。在此基础上,根据实际业务,我们可以扩展做出更复杂的效果。最后附上demo地址,谢谢观看。