参考网站:
自定义软键盘(Android)_Wing_LS的博客-CSDN博客
Android自定义键盘的简单实现_xyTianZhao的博客-CSDN博客_android自定义键盘
Dialog上的EditText的自定义键盘_SKY_L1的博客-CSDN博客
Android 4.0设置Dialog点击屏幕不消失_一叶飘舟的博客-CSDN博客
一、代码实现
参考Android 4.0设置Dialog点击屏幕不消失_一叶飘舟的博客-CSDN博客的文章基本可以完成软键盘的展示,对其调整后代码如下:
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 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 keys = new ArrayList();
private int lastKeyIndex = 0;
private Keyboard.Key focusedKey;//当前获取焦点的key
private Rect rect;//表示包裹当前获取焦点的key的方框
private int nCurKeyboardKeyNums;//当前键盘的按键数量
private Keyboard nCurrentKeyboard;
private List 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
symbols.xml
其中键盘上有些字符无法使用字符串展示,只能使用图片展示,可自行设计如(@,&,>,",删除键,切换大小写键,切换数字和字母键,空格键)
二、如何使用
在需要使用的activity对应的xml文件中加入
其中:
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的信息。
以上为我使用自定义键盘的一些总结,有些问题可能也不是很好,后期再进行完善。