最近因为项目需求要自定义一个数字键盘,在网上查了些资料但很多功能不全,很多场景不能适应。今天就结合网上的一些资料打算自己写一个键盘。主要适应二种场景:
1、支付密码 需要随机键盘
2、点击EditText能自动向上顶布局
源码下载地址:http://git.oschina.net/shikh/CustomView-master
先看一下使用方法:
<expand.shikh.com.customview.keyboard.NumberKeyBoardEditText
android:layout_alignParentBottom="true"
android:id="@+id/etChar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="10dp"
android:background="#ace"
android:gravity="center"
android:hint="数字键盘"
android:singleLine="true"
android:textColor="#ffffff"
android:textColorHint="#ffffff"
mykeyboard:xml="@xml/symbols"
mykeyboard:randomkeys="true"
/>
只需引用我们自定义的editText 控件就欧了~
先看一下效果图
下面来说说我们的实现方式:
实现软键盘主要用到了系统的两个类Keyboard和KeyboardView:
Keyboard类源码的介绍是: Listener for virtual keyboard events.即用于监听虚拟键盘。至于Keyboard类的映射机制,这里就不需要说了,要分析源码请移驾http://blog.csdn.net/pi9nc/article/details/27304459
1、在res文件下,新建一个xml文件,下面放数字键盘的布局文件
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="1dp"
android:keyWidth="33.33333%p"
android:verticalGap="1dp">
<Row android:keyHeight="7%p">
<Key android:codes="-3" android:keyIcon="@mipmap/keyboard_back_img" android:keyWidth="100%p" />
</Row>
<Row android:keyHeight="10%p">
<Key android:codes="55" android:keyLabel="7" />
<Key android:codes="56" android:keyLabel="8" />
<Key android:codes="57" android:keyEdgeFlags="right" android:keyLabel="9" />
</Row>
<Row android:keyHeight="10%p">
<Key android:codes="52" android:keyLabel="4" />
<Key android:codes="53" android:keyLabel="5" />
<Key android:codes="54" android:keyEdgeFlags="right" android:keyLabel="6" />
</Row>
<Row android:keyHeight="10%p">
<Key android:codes="49" android:keyLabel="1" />
<Key android:codes="50" android:keyLabel="2" />
<Key android:codes="51" android:keyEdgeFlags="right" android:keyLabel="3" />
</Row>
<Row android:keyHeight="10%p">
<Key android:codes="4896" android:keyLabel="清空" />
<!--<Key
android:codes="46"
android:keyLabel="." />-->
<Key android:codes="48" android:keyLabel="0" />
<!--<Key android:codes="-3" android:keyEdgeFlags="right" android:keyLabel="OK"/>-->
<!--<key android:codes="4896" android:keylabel="清空" />-->
<Key android:codes="-5" android:keyEdgeFlags="right" android:keyIcon="@mipmap/keyboard_delete_img" />
</Row>
</Keyboard>
3、创建键盘的工具类KeyboardUtil(显示键盘的主要代码),如下:
public class KeyboardUtil {
private KeyboardView keyboardView;
private Keyboard k;// 数字键盘
private EditText ed;
private Context mContext;
private PopupWindow mKeyboardWindow;
public Keyboard getK() {
return k;
}
public KeyboardView getKeyboardView() {
return keyboardView;
}
public void setmKeyboardWindow(PopupWindow mKeyboardWindow) {
this.mKeyboardWindow = mKeyboardWindow;
}
/**
* 键盘置于布局文件中
* @author shikh
* @time 2016/12/8 上午10:19
*/
public KeyboardUtil(Activity atx, EditText edit,int keyId,int xmlId){
this.ed = edit;
this.mContext = atx;
k = new Keyboard(atx, xmlId == 0?R.xml.symbols:xmlId);
keyboardView = (KeyboardView) atx.findViewById(keyId);
initKeyBoard();
}
/**
* 键盘用popwindow 形式打开 结合 numberKeyBoardEditText 使用 具有向上顶布局的功能
* @author shikh
* @time 2016/12/8 上午10:22
*/
public KeyboardUtil(Context ctx, EditText edit, int xmlId) {
this.ed = edit;
this.mContext = ctx;
k = new Keyboard(ctx, xmlId == 0?R.xml.symbols:xmlId);
keyboardView = (KeyboardView) View.inflate(ctx,R.layout.layout_keyboard_view,null);
}
public void initKeyBoard(){
keyboardView.setKeyboard(k);
keyboardView.setEnabled(true);
keyboardView.setPreviewEnabled(false);
keyboardView.setVisibility(View.VISIBLE);
keyboardView.setOnKeyboardActionListener(listener);
}
private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {
@Override
public void swipeUp() {}
@Override
public void swipeRight() {}
@Override
public void swipeLeft() {}
@Override
public void swipeDown() {}
@Override
public void onText(CharSequence text) {}
@Override
public void onRelease(int primaryCode) {}
@Override
public void onPress(int primaryCode) {}
//一些特殊操作按键的codes是固定的比如完成、回退等
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = ed.getText();
int start = ed.getSelectionStart();
if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
if (editable != null && editable.length() > 0) {
if (start > 0) {
editable.delete(start - 1, start);
}
}
} else if (primaryCode == 4896) {// 清空
editable.clear();
} else if (primaryCode == Keyboard.KEYCODE_CANCEL) {//
hideKeyboard();
} else if (primaryCode == 46) { // 小数点
String text = ed.getText().toString();
if (!text.contains(".") && text.length() >0) {
editable.insert(start, Character.toString((char) primaryCode));
}
} else { //将要输入的数字现在编辑框中
editable.insert(start, Character.toString((char) primaryCode));
}
}
};
/**
* 实应于 键盘布局放置在activity 布局文件中
* @author shikh
* @time 2016/12/8 上午10:08
*/
public boolean isShow() {
int visibility = keyboardView.getVisibility();
if (visibility == View.VISIBLE) {
return true;
}
return false;
}
public void showKeyboard() {
int visibility = keyboardView.getVisibility();
if (visibility == View.GONE || visibility == View.INVISIBLE) {
keyboardView.setVisibility(View.VISIBLE);
}
}
public void hideKeyboard() {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
}
}else {
int visibility = keyboardView.getVisibility();
if (visibility == View.VISIBLE) {
keyboardView.setVisibility(View.GONE);
}
}
}
/**
* 隐藏系统键盘
* @author shikh
* @time 2016/12/8 下午3:19
*/
public void hideSoftInputMethod(Window mWindow) {
mWindow.setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
int currentVersion = android.os.Build.VERSION.SDK_INT;
String methodName = null;
if (currentVersion >= 16) {
// 4.2
methodName = "setShowSoftInputOnFocus";
} else if (currentVersion >= 14) {
// 4.0
methodName = "setSoftInputShownOnFocus";
}
if (methodName == null) {
ed.setInputType(InputType.TYPE_NULL);
} else {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus;
try {
setShowSoftInputOnFocus = cls.getMethod(methodName,
boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(ed, false);
} catch (NoSuchMethodException e) {
ed.setInputType(InputType.TYPE_NULL);
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
4、自定义EditText 控件NumberKeyBoardEditText ,实现触摸弹出自定义键盘,先要创建一个 KeyBoardView 布局供 popupWindow使用
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboard_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#dddddd"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyBackground="@drawable/bg_keyboard_btn"
android:keyTextColor="@color/keyTextColor"
android:keyTextSize="24sp"
android:paddingTop="1dp"
android:shadowRadius="0.0"
android:visibility="gone" />
NumberKeyBoardEditText 类的主要代码
public NumberKeyBoardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttributes(context);
initKeyBoard(context, attrs);
initPopWindow();
}
private void initKeyBoard(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.keyboard);
if (a.hasValue(R.styleable.keyboard_xml)) {
needcustomkeyboard = true;
int xmlid = a.getResourceId(R.styleable.keyboard_xml, 0);
keyboardUtil = new KeyboardUtil(context, this, xmlid);
} else {
keyboardUtil = new KeyboardUtil(context, this, 0);
}
if (a.hasValue(R.styleable.keyboard_randomkeys)) {
randomkeys = a.getBoolean(R.styleable.keyboard_randomkeys, false);
}
mKeyboardView = keyboardUtil.getKeyboardView();
mKeyboard = keyboardUtil.getK();
if (randomkeys) {//随机键盘
randomdigkey(mKeyboard);
}
keyboardUtil.initKeyBoard();
a.recycle();
}
private void initPopWindow() {
mKeyboardWindow = new PopupWindow(keyboardUtil.getKeyboardView(), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mKeyboardWindow.setAnimationStyle(R.style.AnimationFade);//设置动画效果,文件在资源里面,这里就不贴出来。</span></strong>
// mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable());
// mKeyboardWindow.setOutsideTouchable(true);
keyboardUtil.setmKeyboardWindow(mKeyboardWindow);
mKeyboardWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
// TODO Auto-generated method stub
if (scrolldis > 0) {
int temp = scrolldis;
scrolldis = 0;
if (null != mContentView) {
//使布局整体向上顶的关键代码,使用布局的scrollBy重新滚动位置
mContentView.scrollBy(0, -temp);
}
}
}
});
}
// 暂时未使用到,为了实现随机键盘布局
private void randomdigkey(Keyboard mKeyboard) {
if (mKeyboard == null) {
return;
}
List<Keyboard.Key> keyList = mKeyboard.getKeys();
// 查找出0-9的数字键
List<Keyboard.Key> newkeyList = new ArrayList<Keyboard.Key>();
for (int i = 0, size = keyList.size(); i < size; i++) {
Keyboard.Key key = keyList.get(i);
CharSequence label = key.label;
if (label != null && isNumber(label.toString())) {
newkeyList.add(key);
}
}
int count = newkeyList.size();
List<KeyModel> resultList = new ArrayList<KeyModel>();
LinkedList<KeyModel> temp = new LinkedList<KeyModel>();
for (int i = 0; i < count; i++) {
temp.add(new KeyModel(48 + i, i + ""));
}
Random rand = new SecureRandom();
rand.setSeed(SystemClock.currentThreadTimeMillis());
for (int i = 0; i < count; i++) {
int num = rand.nextInt(count - i);
KeyModel model = temp.get(num);
resultList.add(new KeyModel(model.getCode(), model.getLable()));
temp.remove(num);
}
for (int i = 0, size = newkeyList.size(); i < size; i++) {
Keyboard.Key newKey = newkeyList.get(i);
KeyModel resultmodle = resultList.get(i);
newKey.label = resultmodle.getLable();
newKey.codes[0] = resultmodle.getCode();
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
requestFocus();
requestFocusFromTouch();
// if (needcustomkeyboard) {
hideSysInput();
showKeyboard();
// }
return true;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
return true;
}
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
this.mWindow = ((Activity) getContext()).getWindow();
this.mDecorView = this.mWindow.getDecorView();
this.mContentView = this.mWindow.findViewById(Window.ID_ANDROID_CONTENT);
// hideSysInput();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
hideKeyboard();
mKeyboardWindow = null;
mKeyboardView = null;
mKeyboard = null;
mDecorView = null;
mContentView = null;
mWindow = null;
}