目录
1.场景:
项目中有定制的设备需要放在室外,用户使用时使用系统自带的键盘肯能没有那么方便,所以就需要使用到了自定义键盘
(结尾附上完整代码可以直接使用,不想看过程的可以直接跳过)
2.想法:
封装成一个比较通用的,当成一个View一样来使用
**实现自定义键盘思路:**
1. 在res包下创建xml目录,Keyboard标签来定义键盘布局
2. 创建IKeyboardView类并继承KeyboardView类,设置键盘布局(数字和字母)
3. 处理自定义键盘按键的点击事件以及预览,并实现数字和字母键盘(包括大小写)之间的切换
4. 绑定EditText,并且屏蔽系统键盘(实现点击切换绑定多个EditText)
5. 使用
3.开始实现:
《一》 在res包下创建xml目录,Keyboard标签来定义键盘布局:
创建keyboard_num.xml文件(数字键盘布局)
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="10%p"
android:keyHeight="7%p"
android:horizontalGap="0.0px"
android:verticalGap="0.0px">
<Row android:verticalGap="1%p">
<Key
android:codes="113"
android:keyLabel="q"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="119"
android:keyLabel="w"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="101"
android:keyLabel="e"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="114"
android:keyLabel="r"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="116"
android:keyLabel="t"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="121"
android:keyLabel="y"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="117"
android:keyLabel="y"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="105"
android:keyLabel="i"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="111"
android:keyLabel="o"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="112"
android:keyLabel="p"
android:horizontalGap="1.81%p">
</Key>
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="97"
android:keyLabel="a"
android:keyWidth="9%p"
android:horizontalGap="5.5%p">
</Key>
<Key
android:codes="115"
android:keyLabel="s"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="100"
android:keyLabel="d"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="102"
android:keyLabel="f"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="103"
android:keyLabel="g"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="104"
android:keyLabel="h"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="106"
android:keyLabel="j"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="107"
android:keyLabel="k"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="108"
android:keyLabel="l"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="-1"
android:keyLabel="大写"
android:keyWidth="17%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="122"
android:keyLabel="z"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="120"
android:keyLabel="x"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="99"
android:keyLabel="c"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="118"
android:keyLabel="v"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="98"
android:keyLabel="b"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="110"
android:keyLabel="n"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="109"
android:keyLabel="m"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyWidth="17%p"
android:horizontalGap="1%p">
</Key>
</Row>
<Row>
<Key
android:codes="-2"
android:keyLabel="123"
android:keyWidth="20%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="32"
android:keyLabel="space"
android:keyWidth="48%p"
android:horizontalGap="5%p">
</Key>
<Key
android:codes="-4"
android:keyLabel="完成"
android:keyWidth="20%p"
android:horizontalGap="5%p">
</Key>
</Row>
</Keyboard>
创建keyboard_letter.xml文件(字母键盘布局)
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="10%p"
android:keyHeight="7%p"
android:horizontalGap="0.0px"
android:verticalGap="0.0px">
<Row android:verticalGap="1%p">
<Key
android:codes="113"
android:keyLabel="q"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="119"
android:keyLabel="w"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="101"
android:keyLabel="e"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="114"
android:keyLabel="r"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="116"
android:keyLabel="t"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="121"
android:keyLabel="y"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="117"
android:keyLabel="y"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="105"
android:keyLabel="i"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="111"
android:keyLabel="o"
android:horizontalGap="1.81%p">
</Key>
<Key
android:codes="112"
android:keyLabel="p"
android:horizontalGap="1.81%p">
</Key>
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="97"
android:keyLabel="a"
android:keyWidth="9%p"
android:horizontalGap="5.5%p">
</Key>
<Key
android:codes="115"
android:keyLabel="s"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="100"
android:keyLabel="d"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="102"
android:keyLabel="f"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="103"
android:keyLabel="g"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="104"
android:keyLabel="h"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="106"
android:keyLabel="j"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="107"
android:keyLabel="k"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="108"
android:keyLabel="l"
android:keyWidth="9%p"
android:horizontalGap="1%p">
</Key>
</Row>
<Row android:verticalGap="1%p">
<Key
android:codes="-1"
android:keyLabel="大写"
android:keyWidth="17%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="122"
android:keyLabel="z"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="120"
android:keyLabel="x"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="99"
android:keyLabel="c"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="118"
android:keyLabel="v"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="98"
android:keyLabel="b"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="110"
android:keyLabel="n"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="109"
android:keyLabel="m"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyWidth="17%p"
android:horizontalGap="1%p">
</Key>
</Row>
<Row>
<Key
android:codes="-2"
android:keyLabel="123"
android:keyWidth="20%p"
android:horizontalGap="1%p">
</Key>
<Key
android:codes="32"
android:keyLabel="space"
android:keyWidth="48%p"
android:horizontalGap="5%p">
</Key>
<Key
android:codes="-4"
android:keyLabel="完成"
android:keyWidth="20%p"
android:horizontalGap="5%p">
</Key>
</Row>
</Keyboard>
《二》创建IKeyboardView类并继承KeyboardView类,设置键盘布局(数字和字母)
public class IKeyBoardView extends KeyboardView implements KeyboardView.OnKeyboardActionListener {
public IIKeyBoardView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public IKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public IIKeyBoardView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
/**
* 数字键盘
*/
private Keyboard keyboardNumber;
/**
* 字母键盘
*/
private Keyboard keyboardLetter;
//绑定的输入框
private EditText mEditText;
/**
* 是否发生键盘切换
*/
private boolean changeLetter = false;
/**
* 是否为大写
*/
private boolean isCapital = false;
private List<Integer> noLists = new ArrayList<>();
private int[] arrays = new int[]{Keyboard.KEYCODE_SHIFT, Keyboard.KEYCODE_MODE_CHANGE,
Keyboard.KEYCODE_CANCEL, Keyboard.KEYCODE_DONE, Keyboard.KEYCODE_DELETE,
Keyboard.KEYCODE_ALT, 32};
//初始化
private void init(){
keyboardNumber = new Keyboard(getContext(), R.xml.keyboard_num);
keyboardLetter = new Keyboard(getContext(), R.xml.keyboard_letter);
//设置一些不需要预览的键位
for (int i = 0; i < arrays.length; i++) {
noLists.add(arrays[i]);
}
//默认使用数字键盘
setKeyboard(keyboardNumber);
//是否启用预览
setPreviewEnabled(true);
//键盘动作监听
setOnKeyboardActionListener(this);
}
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
}
《三》 处理自定义键盘按键的点击事件以及预览,并实现数字和字母键盘(包括大小写)之间的切换
核心代码onKey方法(设置键盘输入)
//在onKey回调中的代码
Editable editable = mEditText.getText();
int start = mEditText.getSelectionStart();
switch (primaryCode) {
case Keyboard.KEYCODE_DELETE://删除
if (editable != null && editable.length() > 0 && start > 0) {
editable.delete(start - 1, start);
}
break;
case Keyboard.KEYCODE_MODE_CHANGE://字母键盘与数字键盘切换
changeKeyBoard(!changeLetter);
break;
case Keyboard.KEYCODE_DONE://完成
changeKeyBoard(!changeLetter);
break;
case Keyboard.KEYCODE_SHIFT://大小写切换
changeCapital(!isCapital);
setKeyboard(keyboardLetter);
break;
default:
editable.insert(start, Character.toString((char) primaryCode));
break;
}
还有几个必要的方法附上
/**
* 切换键盘大小写
*/
private void changeCapital(boolean b) {
isCapital = b;
List<Keyboard.Key> lists = keyboardLetter.getKeys();
for (Keyboard.Key key : lists) {
if (key.label != null && isKey(key.label.toString())) {
if (isCapital) {
key.label = key.label.toString().toUpperCase();
key.codes[0] = key.codes[0] - 32;
} else {
key.label = key.label.toString().toLowerCase();
key.codes[0] = key.codes[0] + 32;
}
} else if (key.label != null && key.label.toString().equals("小写")) {
key.label = "大写";
} else if (key.label != null && key.label.toString().equals("大写")) {
key.label = "小写";
}
}
}
/**
* 判断此key是否正确,且存在 * * @param key * @return
*/
private boolean isKey(String key) {
String lowercase = "abcdefghijklmnopqrstuvwxyz";
if (lowercase.indexOf(key.toLowerCase()) > -1) {
return true;
}
return false;
}
/**
* 切换键盘类型
*/
private void changeKeyBoard(boolean b) {
changeLetter = b;
if (b) {
setKeyboard(keyboardLetter);
} else {
setKeyboard(keyboardNumber);
}
}
/**
* 判断是否需要预览Key
*
* @param primaryCode keyCode
*/
private void canShowPreview(int primaryCode) {
if (noLists.contains(primaryCode)) {
setPreviewEnabled(false);
} else {
setPreviewEnabled(true);
}
}
//设置需要绑定的EditView
public void setmEditText(EditText mEditText) {
this.mEditText = mEditText;
}
《四》 绑定EditText,并且屏蔽系统键盘(实现点击切换绑定多个EditText)
这块我屏蔽键盘的方式是比较粗暴的,直接在EditTextView当中设置了屏蔽焦点,这样的同时会让EditTextView丢失光标
public class IEditText extends AppCompatEditText {
private IKeyboardView mIKeyboardView;
public IEditText(@NonNull Context context) {
super(context);
init();
}
public IEditText(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public IEditText(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setInputType(InputType.TYPE_NULL);
}
//绑定键盘
public void setmIKeyboardView(IKeyboardView mIKeyboardView) {
this.mIKeyboardView = mIKeyboardView;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//按下时绑定当前的EditText
if (event.getAction() == MotionEvent.ACTION_DOWN){
if (mIKeyboardView!=null){
mIKeyboardView.setEditText(this);
}
}
return super.onTouchEvent(event);
}
}
《五》. 使用
例如:两个EditTextView一个自定义键盘,因为太简单我就不放出布局代码了(占位置) 就看看咱是如何绑定的
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity:";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivityBinding binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
//默认绑定一个EditTextView
binding.viewKeyboard.setEditText(binding.ed1);
//点击时切换绑定键盘
binding.ed1.setmIKeyboardView(binding.viewKeyboard);
binding.ed2.setmIKeyboardView(binding.viewKeyboard);
}
}
4.KeyboardView,keyboard,Key,Row属性解释:
- Keyboard
- Row
- Key
- KeyboardView
![在这里插入图片描述](https://img-blog.csdnimg.cn/1e5efd3bbb8248af91cf6beb1ab6b913.png
5.完整代码
https://gitee.com/li-weihao1010/keyboard
6.注意事项
在清单文件(AndroidManifest.xml)中,
activity标签下面不要使用该属性
android:hardwareAccelerated=“true”
不然会导致你键盘卡顿以及点击事件错位问题
6.结尾
如果大家觉得有哪里写得有问题,可以告诉我,一起学习
参考链接