一、代码实现
对其调整后代码如下:
KeyboardUtil
package xxx.xxx.xxx.softKeyboard;
import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Editable;
import android.view.View;
import android.widget.EditText;
import xxx.xxx.xxx.R;
import xxx.xxx.xxx.util.LogUtils;
import java.util.List;
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.qwenty);
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监听
KeyboardView.OnKeyboardActionListener listener = new KeyboardView.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();
//LogUtils.e("=4=","onKey:" + primaryCode);
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<Keyboard.Key> keys = kQwerty.getKeys();
for (Keyboard.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;
}
}
CKeyboardView
package xxx.xxx.xxx.softKeyboard;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.AttributeSet;
import android.view.KeyEvent;
import java.util.ArrayList;
import java.util.List;
public class CKeyboardView extends KeyboardView {
private Keyboard currentKeyboard;
private List<Keyboard.Key> keys = new ArrayList<Keyboard.Key>();
private int lastKeyIndex = 0;
private Keyboard.Key focusedKey;//当前获取焦点的key
private Rect rect;//表示包裹当前获取焦点的key的方框
private int nCurKeyboardKeyNums;//当前键盘的按键数量
private Keyboard nCurrentKeyboard;
private List<Keyboard.Key> nKeys;//按键集合
private int nLastKeyIndex = 0;
@Override
public void setKeyboard(Keyboard keyboard) {
super.setKeyboard(keyboard);
}
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(Paint.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) {
Keyboard.Key nearKey = nKeys.get(index);
Keyboard.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) {
Keyboard.Key nearKey = nKeys.get(index);
Keyboard.Key nextNearKey = nKeys.get(index + 1);
Keyboard.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);
}
}
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="@mipmap/icon_s_top"
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="@mipmap/icon_s_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="@mipmap/icon_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:keyIcon="@mipmap/icon_aite" />
<Key
android:codes="35"
android:keyLabel="#" />
<Key
android:codes="36"
android:keyLabel="$" />
<Key
android:codes="37"
android:keyLabel="%" />
<Key
android:codes="38"
android:keyIcon="@mipmap/icon_yu"
/>
<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:keyIcon="@mipmap/icon_shuang1"/>
<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:keyIcon="@mipmap/icon_wenhao"/>
<Key
android:codes="43"
android:keyLabel="+" />
<Key
android:codes="-5"
android:isRepeatable="true"
android:keyEdgeFlags="right"
android:keyIcon="@mipmap/icon_s_delete"
/>
</Row>
<Row android:rowEdgeFlags="bottom" >
<Key
android:codes="-2"
android:keyLabel="ABC"
android:keyWidth="20%p" />
<Key
android:codes="60"
android:keyIcon="@mipmap/icon_xiao"
android:keyWidth="12%p"/>
<Key
android:codes="62"
android:keyIcon="@mipmap/icon_da"
android:keyWidth="12%p" />
<Key
android:codes="32"
android:isRepeatable="true"
android:keyIcon="@mipmap/icon_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>
其中键盘上有些字符无法使用字符串展示,只能使用图片展示,可自行设计如(@,&,>,",删除键,切换大小写键,切换数字和字母键,空格键)
二、如何使用
在需要使用的activity对应的xml文件中加入
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<xxx.xxx.xxx.softKeyboard.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="@mipmap/login_bgc"
android:background="@mipmap/bg_keyboard"
android:keyBackground="@mipmap/bg_keyboard"
-->
</RelativeLayout>
其中:
android:background="@mipmap/bt_background_active" 设置键盘背景
android:keyBackground="@mipmap/bt_background_active" 设置按键背景
android:keyTextColor="@color/black" 设置按键文字颜色
android:shadowColor="@color/white" 设置按键文字阴影颜色
android:shadowRadius="0" 设置阴影半径
因为我们的需求是隐藏按键的动态效果,因此加入了以上的属性。
在对应的EditText加上监听让点击后自定义键盘显示,代码如下:
passwordEditText = findViewById(R.id.password);
passwordEditText.setTransformationMethod(new MyTransformation());//可以隐藏密码输入类型时,短暂按键值的显示
passwordEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean b) {
keyboardUtil.setEditText(passwordEditText);
keyboardUtil.showKeyboard();
}
});
MyTransformation,这个可以根据需要进行自行设定
package xxx.xxx.xxx.ui.other;
import android.text.method.PasswordTransformationMethod;
import android.view.View;
public class MyTransformation extends PasswordTransformationMethod {
@Override
public CharSequence getTransformation(CharSequence source, View view) {
return new PasswordCharSequence(source);
}
private class PasswordCharSequence implements CharSequence {
private CharSequence mSource;
public PasswordCharSequence(CharSequence source) {
mSource = source; // Store char sequence
}
public char charAt(int index) {
return '*'; // This is the important part
}
public int length() {
return mSource.length(); // Return default
}
public CharSequence subSequence(int start, int end) {
return mSource.subSequence(start, end); // Return default
}
}
}
以上就完成了简单的自定义键盘的使用。
三、遇到的问题
1,软键盘的关闭,当点击键盘和输入框以外的地方需要隐藏软键盘,代码如下:
//隐藏软键盘,输入框失去焦点
public void hideSoftKeyboard()
{
LogUtils.e("=1=","2222222222222222");
usernameEditText.clearFocus();
passwordEditText.clearFocus();
//Hides the SoftKeyboard
View view = this.getWindow().getDecorView();
//系统软件盘的关闭
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); //强制隐藏键盘
//自定义键盘
keyboardUtil.hideKeyboard();
}
/**
* 关闭EditText以外的任何地方的SoftKeyboard onTouch
* @param view
*/
public void setupUI(View view)
{
if (!(view instanceof EditText || view instanceof CKeyboardView)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard();
return false;
}
});
}
//If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
在activity的onCreate方法中调用setupUI即可。
2.当fragment中需要使用软键盘,需要其activity的xml中加入软键盘的布局代码片段,然后再activity中定义keyboardUtil,然后再通过fragment的构造函数传递到其中,然后再在fragment使用,同样在activity和fragment中调用隐藏代码片段。
3.自定义对话框中使用了EditText,并且使用自定义键盘,同样需要通过构造函数将keyboardUtil对象传递,然后进行使用,并且可以通过
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
来强制使用自定键盘。
因为我们项目的问题,需要插入IC读卡器,所有有些页面没法使用以上设置,不然则无法读取到IC的信息。
以上为我使用自定义键盘的一些总结,有些问题可能也不是很好,后期再进行完善。