去年因公司需要给电视盒子做一个自定义键盘,今天偶然想起来, 想趁此机会记录一下。
当时好像是下载了一个别人的例子,参考着改了一下。具体是哪个作者分享的demo已无法追寻了,先在此表示感谢。
此demo功能中,只能输入英文和常用字符,尚未兼顾输入中文功能。
效果图如下:
1.继承KeyboardView,重写onKeyDown方法:
public class CKeyboardView extends KeyboardView {
private Keyboard currentKeyboard;
private List keys = new ArrayList();
private int lastKeyIndex = 0;
private Key focusedKey;//当前获取焦点的key
private Rect rect;//表示包裹当前获取焦点的key的方框
private int nCurKeyboardKeyNums;//当前键盘的按键数量
private Keyboard nCurrentKeyboard;
private List nKeys;//按键集合
private int nLastKeyIndex = 0;
public CKeyboardView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//获取当前键盘
currentKeyboard = this.getKeyboard();
keys = currentKeyboard.getKeys();
//当前获取焦点的key画方框,表示选中的是当前key
Paint p = new Paint();
p.setColor(Color.parseColor("#33ffff"));
p.setStyle(Style.STROKE);
p.setStrokeWidth(3.75f);
focusedKey = keys.get(lastKeyIndex);
rect = new Rect(focusedKey.x, focusedKey.y + 4, focusedKey.x
+ focusedKey.width, focusedKey.y + focusedKey.height);
canvas.drawRect(rect, p);
}
public int getLastKeyIndex() {
return lastKeyIndex;
}
public void setLastKeyIndex(int lastKeyIndex) {
this.lastKeyIndex = lastKeyIndex;
}
private void setFields() {
nCurrentKeyboard = this.getKeyboard();
nKeys = nCurrentKeyboard.getKeys();
nCurKeyboardKeyNums = nKeys.size();
nLastKeyIndex = this.getLastKeyIndex();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//Toast.makeText(this.getContext(), "onKeyDown--"+keyCode, Toast.LENGTH_LONG).show();
Log.d("tag", keyCode + "---" + event.getAction());
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:// 返回 4
if (event.getRepeatCount() == 0) {
if (this.handleBack()) {
return true;
}
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:// 向下 20
setFields();
if (nLastKeyIndex >= nCurKeyboardKeyNums - 1) {
this.setLastKeyIndex(0);
} else {
int x = nKeys.get(nLastKeyIndex).x;
int y = nKeys.get(nLastKeyIndex).y;
int[] nearestKeys = nCurrentKeyboard.getNearestKeys(x, y);
for (int index : nearestKeys) {
if (nLastKeyIndex < index) {
Key nearKey = nKeys.get(index);
Key lastKey = nKeys.get(nLastKeyIndex);
if (((lastKey.x >= nearKey.x) // left side compare
&& (lastKey.x < (nearKey.x + nearKey.width)))
|| (((lastKey.x + lastKey.width) > nearKey.x) // right
// side
// compare
&& ((lastKey.x + lastKey.width) <= (nearKey.x + nearKey.width)))) {
this.setLastKeyIndex(index);
break;
}
}
}
}
this.invalidate();
return true;
case KeyEvent.KEYCODE_DPAD_UP:// 向上19
setFields();
if (nLastKeyIndex <= 0) {
this.setLastKeyIndex(nCurKeyboardKeyNums - 1);
} else {
int x = nKeys.get(nLastKeyIndex).x;
int y = nKeys.get(nLastKeyIndex).y;
int[] nearestKeys = nCurrentKeyboard.getNearestKeys(x, y);
for (int i = nearestKeys.length - 1; i >= 0; i--) {
int index = nearestKeys[i];
if (nLastKeyIndex > index) {
Key nearKey = nKeys.get(index);
Key nextNearKey = nKeys.get(index + 1);
Key lastKey = nKeys.get(nLastKeyIndex);
if ((lastKey.x >= nearKey.x && lastKey.x < (nearKey.x + nearKey.width))
&& ((lastKey.x + lastKey.width) <= (nextNearKey.x + nextNearKey.width) || lastKey.x
+ lastKey.width > nextNearKey.x)) {
this.setLastKeyIndex(index);
break;
}
}
}
}
this.invalidate();
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:// 左21
setFields();
if (nLastKeyIndex <= 0) {
this.setLastKeyIndex(nCurKeyboardKeyNums - 1);
} else {
nLastKeyIndex--;
this.setLastKeyIndex(nLastKeyIndex);
}
this.invalidate();
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:// 右22
setFields();
if (nLastKeyIndex >= nCurKeyboardKeyNums - 1) {
this.setLastKeyIndex(0);
} else {
nLastKeyIndex++;
this.setLastKeyIndex(nLastKeyIndex);
}
this.invalidate();
return true;
case KeyEvent.KEYCODE_ENTER://66
case KeyEvent.KEYCODE_DPAD_CENTER://23
setFields();
int currentKeyCode = nKeys.get(nLastKeyIndex).codes[0];
switch (currentKeyCode) {
case Keyboard.KEYCODE_MODE_CHANGE:
case Keyboard.KEYCODE_CANCEL:
case Keyboard.KEYCODE_DELETE:
case Keyboard.KEYCODE_SHIFT:
getOnKeyboardActionListener().onKey(currentKeyCode, null);
return true;
default:
getOnKeyboardActionListener().onKey(currentKeyCode, null);
return true;
}
}
return super.onKeyDown(keyCode, event);
}
}
2.创建2个xml,表示字母键盘和符号数字键盘。
qwenty.xml
symbols.xml
3.创建KeyboardUtil,控制键盘
public class KeyboardUtil {
private Context context;
private KeyboardView keyboardView;
private Keyboard kQwerty;//字母键盘
private Keyboard kSymbols;//符号键盘
private boolean isNum = false;//是否是数字
private boolean isSupper = false;//是否大写
private EditText editText;
private boolean isShown = false;
/**
* 构造方法
*
* @param context 上下文
* @param editText 需要输入的EditView
* @param pView KeyboardView所在的父控件
*/
public KeyboardUtil(Context context, EditText editText, View pView) {
this.context = context;
this.editText = editText;
//创建字母和符号键盘
kQwerty = new Keyboard(context, R.xml.qwerty);
kSymbols = new Keyboard(context, R.xml.symbols);
//找到KeyboardView
this.keyboardView = (KeyboardView) pView
.findViewById(R.id.keyboard_view);
this.keyboardView.setKeyboard(kQwerty);
this.keyboardView.setEnabled(true);
this.keyboardView.setPreviewEnabled(false);
this.keyboardView.setOnKeyboardActionListener(listener);
}
//Keyboard监听
OnKeyboardActionListener listener = new OnKeyboardActionListener() {
@Override
public void swipeUp() {
// TODO Auto-generated method stub
}
@Override
public void swipeRight() {
// TODO Auto-generated method stub
}
@Override
public void swipeLeft() {
// TODO Auto-generated method stub
}
@Override
public void swipeDown() {
// TODO Auto-generated method stub
}
@Override
public void onText(CharSequence text) {
// TODO Auto-generated method stub
}
@Override
public void onRelease(int primaryCode) {
// TODO Auto-generated method stub
}
@Override
public void onPress(int primaryCode) {
// TODO Auto-generated method stub
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
// Toast.makeText(context, "onKey--"+primaryCode,
// Toast.LENGTH_LONG).show();
Editable editable = editText.getText();
int start = editText.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_CANCEL) {
// 取消,隐藏键盘
hideKeyboard();
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {
// 删除回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
// 大小写切换
changeKey();
keyboardView.setKeyboard(kQwerty);
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
((CKeyboardView) keyboardView).setLastKeyIndex(0);
// 数字键盘切换
if (isNum) {
keyboardView.setKeyboard(kQwerty);
} else {
keyboardView.setKeyboard(kSymbols);
}
isNum = !isNum;
} else {
editable.insert(start, Character.toString((char) primaryCode));
}
}
};
public KeyboardView getKeyboardView() {
return keyboardView;
}
public EditText getEditText() {
return editText;
}
public void setEditText(EditText editText) {
this.editText = editText;
}
//变换大小写
private void changeKey() {
List keys = kQwerty.getKeys();
for (Key key : keys) {
if (key.label != null && isWord(String.valueOf(key.label))) {
if (isSupper) {// up to low
key.label = key.label.toString().toLowerCase();
key.codes[0] = key.codes[0] + 32;
} else {
key.label = key.label.toString().toUpperCase();
key.codes[0] = key.codes[0] - 32;
}
}
}
isSupper = !isSupper;
}
private boolean isWord(String s) {
String reg = "[a-zA-Z]{1}";
return s.matches(reg);
}
//显示键盘
public void showKeyboard() {
int visibility = keyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE) {
keyboardView.setVisibility(View.VISIBLE);
setShown(true);
}
}
//隐藏键盘
public void hideKeyboard() {
if (keyboardView.getVisibility() == View.VISIBLE) {
keyboardView.setVisibility(View.GONE);
setShown(false);
}
}
public boolean isShown() {
return isShown;
}
public void setShown(boolean isShown) {
this.isShown = isShown;
}
}
4.在布局中使用KeyboardView,在Activity中调用
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private KeyboardUtil keyboardUtil;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View view = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
setContentView(view);
EditText editText = (EditText) findViewById(R.id.edit);
editText.setOnClickListener(this);
keyboardUtil = new KeyboardUtil(this, editText, view);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.edit:
if (keyboardUtil.isShown()
&& keyboardUtil.getEditText().getId() == v.getId()) {
keyboardUtil.hideKeyboard();
} else {
keyboardUtil.setEditText((EditText) v);
keyboardUtil.showKeyboard();
}
break;
}
}
@Override
public void onBackPressed() {
// 如果输入法显示,则隐藏输入法,不关闭PopupWindow
if (keyboardUtil != null && keyboardUtil.isShown()) {
keyboardUtil.hideKeyboard();
} else {
super.onBackPressed();
}
}
}
demo地址