# CustomKeyboardView
**Repository Path**: dizner/CustomKeyboardView
## Basic Information
- **Project Name**: CustomKeyboardView
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-03-20
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# CustomKeyboardView
android自定义键盘、自定义身份证键盘、支持拓展。
android 系统键盘支持的点已经比较丰富了, 但是有时候某一些需求还不能满足我们的需求。最近公司应用到了实名认证相关的功能,这部分需要一个身份证的EditText, 自然也需要一个身份证的键盘,奈何系统没有这种键盘,只能自定义一个。
首先来看android SDK为我们提供**Keyboard**的这个类。
1、Keyboard xml描述文件

上面已经描述的很清晰了, 它用来加载一个键盘和存储按键属性的一个描述XML。我们在res/xml 目录下新建一个idcard_keyboard.xml文件。
```
```
这里主要介绍一些常用的类属性,更多请参考[andorid官网](https://developer.android.google.cn/reference/android/inputmethodservice/Keyboard.html)。
- 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类型的自定义属性引入我们的键盘描述文件。
```
```
还需要一个keyboardView 布局文件
```
```
万事俱备、主角登场~~~
```
/**
* 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 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 cls = EditText.class;
Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(this, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 隐藏自定义键盘
*/
private void hideKeyboard() {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
}
}
}
/**
* 隐藏系统键盘
*/
private void hideSysInput() {
if (this.getWindowToken() != null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
@Override
public void onClick(View v) {
requestFocus();
requestFocusFromTouch();
hideSysInput();
showKeyboard();
}
}
```
代码中注释写的已经很清晰了,就不做一一的讲解了。
结尾
- 该自定义组件目前只是支持了身份证键盘,xml下只提供了身份证键盘的描述文件。如果需要其他键盘可以自己定义xml文件,如果有特殊点击事件,逻辑放入`public void onKey(int primaryCode, int[] keyCodes) ` case 相应的keycode逻辑下即可。
- 代码已放入[github https://github.com/zyl409214686/CustomKeyboardView](https://github.com/zyl409214686/CustomKeyboardView),欢迎提 issues、star、Fork。
- 效果图:

参考:
- [android开发者官网](https://developer.android.google.cn/reference/android/inputmethodservice/Keyboard.html)
- [Android 总结:自定义键盘实现原理和三种实例详解](http://blog.csdn.net/u014136472/article/details/50257245)