最近因為項目需求要自定義一個數字鍵盤,在網上查了些資料但很多功能不全,很多場景不能适應。今天就結合網上的一些資料打算自己寫一個鍵盤。主要适應二種場景:
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 == ?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 == ?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() > ) {
if (start > ) {
editable.delete(start - , start);
}
}
} else if (primaryCode == ) {// 清空
editable.clear();
} else if (primaryCode == Keyboard.KEYCODE_CANCEL) {//
hideKeyboard();
} else if (primaryCode == ) { // 小數點
String text = ed.getText().toString();
if (!text.contains(".") && text.length() >) {
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 >= ) {
// 4.2
methodName = "setShowSoftInputOnFocus";
} else if (currentVersion >= ) {
// 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, );
keyboardUtil = new KeyboardUtil(context, this, xmlid);
} else {
keyboardUtil = new KeyboardUtil(context, this, );
}
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 > ) {
int temp = scrolldis;
scrolldis = ;
if (null != mContentView) {
//使布局整體向上頂的關鍵代碼,使用布局的scrollBy重新滾動位置
mContentView.scrollBy(, -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 = , 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 = ; i < count; i++) {
temp.add(new KeyModel( + i, i + ""));
}
Random rand = new SecureRandom();
rand.setSeed(SystemClock.currentThreadTimeMillis());
for (int i = ; 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 = , size = newkeyList.size(); i < size; i++) {
Keyboard.Key newKey = newkeyList.get(i);
KeyModel resultmodle = resultList.get(i);
newKey.label = resultmodle.getLable();
newKey.codes[] = 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;
}