去年因公司需要给电视盒子做一个自定义键盘,今天偶然想起来, 想趁此机会记录一下。
当时好像是下载了一个别人的例子,参考着改了一下。具体是哪个作者分享的demo已无法追寻了,先在此表示感谢。
此demo功能中,只能输入英文和常用字符,尚未兼顾输入中文功能。
效果图如下:
1.继承KeyboardView,重写onKeyDown方法:
public class CKeyboardView extends KeyboardView {
private Keyboard currentKeyboard;
private List<Key> keys = new ArrayList<Key>();
private int lastKeyIndex = 0;
private Key focusedKey;//当前获取焦点的key
private Rect rect;//表示包裹当前获取焦点的key的方框
private int nCurKeyboardKeyNums;//当前键盘的按键数量
private Keyboard nCurrentKeyboard;
private List<Key> 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
<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0.0px"
android:keyHeight="8%"
android:keyWidth="10.000002%p"
android:verticalGap="0.0px">
<Row>
<Key
android:codes="113"
android:keyEdgeFlags="left"
android:keyLabel="q" />
<Key
android:codes="119"
android:keyLabel="w" />
<Key
android:codes="101"
android:keyLabel="e" />
<Key
android:codes="114"
android:keyLabel="r" />
<Key
android:codes="116"
android:keyLabel="t" />
<Key
android:codes="121"
android:keyLabel="y" />
<Key
android:codes="117"
android:keyLabel="u" />
<Key
android:codes="105"
android:keyLabel="i" />
<Key
android:codes="111"
android:keyLabel="o" />
<Key
android:codes="112"
android:keyEdgeFlags="right"
android:keyLabel="p" />
</Row>
<Row>
<Key
android:codes="97"
android:horizontalGap="4.999995%p"
android:keyEdgeFlags="left"
android:keyLabel="a" />
<Key
android:codes="115"
android:keyLabel="s" />
<Key
android:codes="100"
android:keyLabel="d" />
<Key
android:codes="102"
android:keyLabel="f" />
<Key
android:codes="103"
android:keyLabel="g" />
<Key
android:codes="104"
android:keyLabel="h" />
<Key
android:codes="106"
android:keyLabel="j" />
<Key
android:codes="107"
android:keyLabel="k" />
<Key
android:codes="108"
android:keyEdgeFlags="right"
android:keyLabel="l" />
</Row>
<Row>
<Key
android:codes="-1"
android:isModifier="true"
android:isSticky="true"
android:keyEdgeFlags="left"
android:keyIcon="@drawable/sym_keyboard_shift"
android:keyWidth="14.999998%p" />
<Key
android:codes="122"
android:keyLabel="z" />
<Key
android:codes="120"
android:keyLabel="x" />
<Key
android:codes="99"
android:keyLabel="c" />
<Key
android:codes="118"
android:keyLabel="v" />
<Key
android:codes="98"
android:keyLabel="b" />
<Key
android:codes="110"
android:keyLabel="n" />
<Key
android:codes="109"
android:keyLabel="m" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/sym_keyboard_delete"
android:keyWidth="14.999998%p" />
</Row>
<Row android:rowEdgeFlags="bottom">
<Key
android:codes="-2"
android:keyLabel="12#"
android:keyWidth="20.000004%p" />
<Key
android:codes="44"
android:keyLabel=","
android:keyWidth="14.999998%p" />
<Key
android:codes="32"
android:isRepeatable="true"
android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="29.999996%p" />
<Key
android:codes="46"
android:keyLabel="."
android:keyWidth="14.999998%p" />
<Key
android:codes="-3"
android:keyEdgeFlags="right"
android:keyLabel="完成"
android:keyWidth="20.000004%p" />
</Row>
</Keyboard>
symbols.xml
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="0px"
android:keyHeight="8%"
android:keyWidth="10%p"
android:verticalGap="0px" >
<Row>
<Key
android:codes="49"
android:keyLabel="1" />
<Key
android:codes="50"
android:keyLabel="2" />
<Key
android:codes="51"
android:keyLabel="3" />
<Key
android:codes="52"
android:keyLabel="4" />
<Key
android:codes="53"
android:keyLabel="5" />
<Key
android:codes="54"
android:keyLabel="6" />
<Key
android:codes="55"
android:keyLabel="7" />
<Key
android:codes="56"
android:keyLabel="8" />
<Key
android:codes="57"
android:keyLabel="9" />
<Key
android:codes="48"
android:keyLabel="0" />
</Row>
<Row>
<Key
android:codes="64"
android:keyLabel="@string/xml_at" />
<Key
android:codes="35"
android:keyLabel="#" />
<Key
android:codes="36"
android:keyLabel="$" />
<Key
android:codes="37"
android:keyLabel="%" />
<Key
android:codes="38"
android:keyLabel="&" />
<Key
android:codes="42"
android:keyLabel="*" />
<Key
android:codes="45"
android:keyLabel="-" />
<Key
android:codes="61"
android:keyLabel="=" />
<Key
android:codes="40"
android:keyLabel="(" />
<Key
android:codes="41"
android:keyLabel=")" />
</Row>
<Row>
<Key
android:codes="95"
android:keyLabel="_" />
<Key
android:codes="33"
android:keyLabel="!" />
<Key
android:codes="34"
android:keyLabel=""" />
<Key
android:codes="39"
android:keyLabel="'" />
<Key
android:codes="58"
android:keyLabel=":" />
<Key
android:codes="59"
android:keyLabel=";" />
<Key
android:codes="47"
android:keyLabel="/" />
<Key
android:codes="63"
android:keyLabel="@string/xml_wh" />
<Key
android:codes="43"
android:keyLabel="+" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@drawable/sym_keyboard_delete"
/>
</Row>
<Row android:rowEdgeFlags="bottom" >
<Key
android:codes="-2"
android:keyLabel="ABC"
android:keyWidth="20%p" />
<Key
android:codes="60"
android:keyLabel="<"
android:keyWidth="12%p"/>
<Key
android:codes="62"
android:keyLabel=">"
android:keyWidth="12%p" />
<Key
android:codes="32"
android:isRepeatable="true"
android:keyIcon="@drawable/sym_keyboard_space"
android:keyWidth="12%p" />
<Key
android:codes="44"
android:keyLabel=","
android:keyWidth="12%p"/>
<Key
android:codes="46"
android:keyLabel="."
android:keyWidth="12%p" />
<Key
android:codes="-3"
android:keyEdgeFlags="right"
android:keyLabel="完成"
android:keyWidth="20%p" />
</Row>
</Keyboard>
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<Key> 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中调用
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.cykj.keyboarddemo.MainActivity">
<EditText
android:id="@+id/edit"
android:layout_width="368dp"
android:layout_height="wrap_content" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.cykj.keyboarddemo.CKeyboardView
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:focusableInTouchMode="true"
android:visibility="gone" />
<!--android:keyTextColor="@android:color/white"
android:background="#ff202020"
android:keyBackground="@drawable/btn_keyboard_key"
-->
</RelativeLayout>
</LinearLayout>
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();
}
}
}