CustomKeyboardView
android自定义键盘、自定义身份证键盘、支持拓展。
Install / Use
/learn @zyl409214686/CustomKeyboardViewREADME
CustomKeyboardView
android自定义键盘、自定义身份证键盘、支持拓展。 android 系统键盘支持的点已经比较丰富了, 但是有时候某一些需求还不能满足我们的需求。最近公司应用到了实名认证相关的功能,这部分需要一个身份证的EditText, 自然也需要一个身份证的键盘,奈何系统没有这种键盘,只能自定义一个。
首先来看android SDK为我们提供Keyboard的这个类。
1、Keyboard xml描述文件

上面已经描述的很清晰了, 它用来加载一个键盘和存储按键属性的一个描述XML。我们在res/xml 目录下新建一个idcard_keyboard.xml文件。
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="2dp"
android:verticalGap="2dp"
android:keyHeight="60dp"
android:keyWidth="33%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="88"
android:keyLabel="X"
/>
<Key
android:codes="48"
android:keyLabel="0" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyIcon="@mipmap/keyboard_del"/>
</Row>
</Keyboard>
这里主要介绍一些常用的类属性,更多请参考andorid官网。
- Keyboard类:存储键盘以及按键相关信息。 android:horizontalGap 按键之间默认的水平间距。 android:verticalGap 按键之间默认的垂直间距。 android:keyHeight 按键的默认高度,以像素或显示高度的百分比表示。 android:keyWidth: 按键的默认宽度,以像素或显示宽度的百分比表示。
- Row:为包含按键的容器。
- Key: 用于描述键盘中单个键的位置和特性。 android:codes 该键输出的unicode值。 android:isRepeatable 这个属性如果设置为true,那么当长按该键时就会重复接受到该键上的动作,在 删除键键 和 空格键 上通常设为true。 android:keyLabel 显示在按键上的文字。 android:keyIcon 与keyLabel是二选一关系,它会代替文字以图标的形式显示在键上。
有了Keyboard来存储键盘相关信息了,那么键盘如何这些信息呢?这时候用到android SDK为我们提供的另外一个类KeyboardView。
2、KeyboardView

KeyboardView是一个渲染虚拟键盘的View。 它处理键的渲染和检测按键和触摸动作。显然我们需要KeyboardView来对Keyboard里的数据进行渲染并呈现给我们以及相关的点击事件做处理。
1)//设置keyboard与KeyboardView相关联的方法。 public void setKeyboard(Keyboard keyboard)
2)//设置虚拟键盘事件的监听,此方法必须设置,不然会报错。 public void setOnKeyboardActionListener(OnKeyboardActionListener listener)
步骤上呢,做完第一步的关联,并设置第二步的事件,调用KeyboardView.setVisible(true);键盘就可以显示出来了, 是不是很简单。不过到这里还没有结束哦,接下来我们为了使用上的便利要进行相应的封装。
封装
这里我们通过继承EditText来对Keyboard与KeyboardView进行封装。
attr.xml文件,这里我们需要通过一个xml类型的自定义属性引入我们的键盘描述文件。
<!-- attr.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Keyboard">
<attr name="xml" format="reference"/>
</declare-styleable>
</resources>
还需要一个keyboardView 布局文件
<!-- KeyboardView 布局文件 -->
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyTextColor="#000000"
android:keyBackground="@drawable/bg_keyboard_btn"
android:keyTextSize="31dp"
android:labelTextSize="23.04sp"
android:background="#e6e6e6"
/>
万事俱备、主角登场~~~
/**
* Description: 自定义键盘类KeyboardEditText
* Created by zouyulong on 2017/7/26.
*/
public class CustomKeyboardEditText extends EditText implements KeyboardView.OnKeyboardActionListener,
View.OnClickListener {
private Keyboard mKeyboard;
private KeyboardView mKeyboardView;
private PopupWindow mKeyboardWindow;
private View mDecorView;
public CustomKeyboardEditText(Context context) {
this(context, null);
}
public CustomKeyboardEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomKeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initKeyboardView(context, attrs);
}
private void initKeyboardView(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Keyboard);
if (!array.hasValue(R.styleable.Keyboard_xml)) {
throw new IllegalArgumentException("you need add keyboard_xml argument!");
}
int xmlId = array.getResourceId(R.styleable.Keyboard_xml, 0);
mKeyboard = new Keyboard(context, xmlId);
mKeyboardView = (KeyboardView) LayoutInflater.from(context).inflate(R.layout.keyboard_view, null);
//键盘关联keyboard对象
mKeyboardView.setKeyboard(mKeyboard);
//关闭键盘按键预览效果,如果按键过小可能会比较适用。
mKeyboardView.setPreviewEnabled(false);
//设置键盘事件
mKeyboardView.setOnKeyboardActionListener(this);
//将keyboardview放入popupwindow方便显示以及位置调整。
mKeyboardWindow = new PopupWindow(mKeyboardView,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
array.recycle();
//设置点击事件,点击后键盘弹起,系统键盘收起。
setOnClickListener(this);
//屏蔽当前edittext的系统键盘
notSystemSoftInput();
}
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = this.getText();
//获取光标偏移量下标
int startIndex = this.getSelectionStart();
switch (primaryCode) {
case Keyboard.KEYCODE_CANCEL:// 隐藏键盘
hideKeyboard();
break;
case Keyboard.KEYCODE_DELETE:// 回退
if (editable != null && editable.length() > 0) {
if (startIndex > 0) {
editable.delete(startIndex - 1, startIndex);
}
}
break;
case 9994://左移
setSelection(startIndex-1);
break;
case 9995://重输
editable.clear();
break;
case 9996://右移
if (startIndex < length()) {
setSelection(startIndex + 1);
}
break;
default:
editable.insert(startIndex, Character.toString((char) primaryCode));
break;
}
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
/**
* 根据key code 获取 Keyboard.Key 对象
* @param primaryCode
* @return
*/
private Keyboard.Key getKeyByKeyCode(int primaryCode) {
if(null != mKeyboard){
List<Keyboard.Key> keyList = mKeyboard.getKeys();
for (int i =0,size= keyList.size(); i < size; i++) {
Keyboard.Key key = keyList.get(i);
int codes[] = key.codes;
if(codes[0] == primaryCode){
return key;
}
}
}
return null;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
return true;
}
}
}
return super.onKeyDown(keyCode, event);
}
@SuppressLint("MissingSuperCall")
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (!focused) {
hideKeyboard();
} else {
hideSysInput();
showKeyboard();
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
this.mDecorView = ((Activity) getContext()).getWindow().getDecorView();
hideSysInput();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
hideKeyboard();
mKeyboardWindow = null;
mKeyboardView = null;
mKeyboard = null;
mDecorView = null;
}
/**
* 显示自定义键盘
*/
private void showKeyboard() {
if (null != mKeyboardWindow) {
if (!mKeyboardWindow.isShowing()) {
mKeyboardView.setKeyboard(mKeyboard);
mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0);
}
}
}
/**
* 屏蔽系统输入法
*/
private void notSystemSoftInput(){
if (Build.VERSION.SDK_INT <= 10) {
setInputType(InputType.TYPE_NULL);
} else {
((Activity)getContext()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
try {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(this, false);
} catch (Exception e) {
e.printStackTrace();
Related Skills
node-connect
343.1kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
90.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.1kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.1kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
