android 系統鍵盤支援的點已經比較豐富了, 但是有時候某一些需求還不能滿足我們的需求。最近公司應用到了實名認證相關的功能,這部分需要一個身份證的EditText, 自然也需要一個身份證的鍵盤,奈何系統沒有這種鍵盤,只能自定義一個。
首先來看android SDK為我們提供Keyboard的這個類。 #####1、Keyboard xml描述檔案
上面已經描述的很清晰了, 它用來載入一個鍵盤和儲存按鍵屬性的一個描述XML。我們在res/xml 目錄下新建一個idcard_keyboard.xml檔案。
<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:horizontalGap="2dp"
android:verticalGap="2dp"
android:keyHeight="60dp"
android:keyWidth="33%p">
<Row>
<Key
android:codes="49"
android:keyLabel="1" />
<Key
android:codes="50"
android:keyLabel="2" />
<Key
android:codes="51"
android:keyLabel="3" />
</Row>
<Row>
<Key
android:codes="52"
android:keyLabel="4" />
<Key
android:codes="53"
android:keyLabel="5" />
<Key
android:codes="54"
android:keyLabel="6" />
</Row>
<Row>
<Key
android:codes="55"
android:keyLabel="7" />
<Key
android:codes="56"
android:keyLabel="8" />
<Key
android:codes="57"
android:keyLabel="9" />
</Row>
<Row>
<Key
android:codes="88"
android:keyLabel="X"
/>
<Key
android:codes="48"
android:keyLabel="0" />
<Key
android:codes="-5"
android:keyIcon="@mipmap/keyboard_del"/>
</Row>
</Keyboard>
複製程式碼
這裡主要介紹一些常用的類屬性,更多請參考andorid官網。
- Keyboard類:儲存鍵盤以及按鍵相關資訊。 android:horizontalGap 按鍵之間預設的水平間距。 android:verticalGap 按鍵之間預設的垂直間距。 android:keyHeight 按鍵的預設高度,以畫素或顯示高度的百分比表示。 android:keyWidth: 按鍵的預設寬度,以畫素或顯示寬度的百分比表示。
- Row:為包含按鍵的容器。
- Key: 用於描述鍵盤中單個鍵的位置和特性。 android:codes 該鍵輸出的unicode值。 android:isRepeatable 這個屬性如果設定為true,那麼當長按該鍵時就會重複接受到該鍵上的動作,在 刪除鍵鍵 和 空格鍵 上通常設為true。 android:keyLabel 顯示在按鍵上的文字。 android:keyIcon 與keyLabel是二選一關係,它會代替文字以圖示的形式顯示在鍵上。
有了Keyboard來儲存鍵盤相關資訊了,那麼鍵盤如何這些資訊呢?這時候用到android SDK為我們提供的另外一個類***KeyboardView***。
#####2、KeyboardView
KeyboardView是一個渲染虛擬鍵盤的View。 它處理鍵的渲染和檢測按鍵和觸控動作。顯然我們需要KeyboardView來對Keyboard裡的資料進行渲染並呈現給我們以及相關的點選事件做處理。
1)//設定keyboard與KeyboardView相關聯的方法。 public void setKeyboard(Keyboard keyboard)
2)//設定虛擬鍵盤事件的監聽,此方法必須設定,不然會報錯。 public void setOnKeyboardActionListener(OnKeyboardActionListener listener)
步驟上呢,做完第一步的關聯,並設定第二步的事件,呼叫KeyboardView.setVisible(true);
鍵盤就可以顯示出來了, 是不是很簡單。不過到這裡還沒有結束哦,接下來我們為了使用上的便利要進行相應的封裝。
#####封裝
這裡我們通過繼承EditText來對Keyboard與KeyboardView進行封裝。
attr.xml檔案,這裡我們需要通過一個xml型別的自定義屬性引入我們的鍵盤描述檔案。
<!-- attr.xml -->
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Keyboard">
<attr name="xml" format="reference"/>
</declare-styleable>
</resources>
複製程式碼
還需要一個keyboardView 佈局檔案
<!-- KeyboardView 佈局檔案 -->
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:keyTextColor="#000000"
android:keyBackground="@drawable/bg_keyboard_btn"
android:keyTextSize="31dp"
android:labelTextSize="23.04sp"
android:background="#e6e6e6"
/>
複製程式碼
萬事俱備、主角登場~~~
/**
* Description: 自定義鍵盤類KeyboardEditText
* Created by zouyulong on 2017/7/26.
*/
public class CustomKeyboardEditText extends EditText implements KeyboardView.OnKeyboardActionListener,
View.OnClickListener {
private Keyboard mKeyboard;
private KeyboardView mKeyboardView;
private PopupWindow mKeyboardWindow;
private View mDecorView;
public CustomKeyboardEditText(Context context) {
this(context, null);
}
public CustomKeyboardEditText(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomKeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initKeyboardView(context, attrs);
}
private void initKeyboardView(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Keyboard);
if (!array.hasValue(R.styleable.Keyboard_xml)) {
throw new IllegalArgumentException("you need add keyboard_xml argument!");
}
int xmlId = array.getResourceId(R.styleable.Keyboard_xml, 0);
mKeyboard = new Keyboard(context, xmlId);
mKeyboardView = (KeyboardView) LayoutInflater.from(context).inflate(R.layout.keyboard_view, null);
//鍵盤關聯keyboard物件
mKeyboardView.setKeyboard(mKeyboard);
//關閉鍵盤按鍵預覽效果,如果按鍵過小可能會比較適用。
mKeyboardView.setPreviewEnabled(false);
//設定鍵盤事件
mKeyboardView.setOnKeyboardActionListener(this);
//將keyboardview放入popupwindow方便顯示以及位置調整。
mKeyboardWindow = new PopupWindow(mKeyboardView,
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
array.recycle();
//設定點選事件,點選後鍵盤彈起,系統鍵盤收起。
setOnClickListener(this);
//遮蔽當前edittext的系統鍵盤
notSystemSoftInput();
}
@Override
public void onPress(int primaryCode) {
}
@Override
public void onRelease(int primaryCode) {
}
@Override
public void onKey(int primaryCode, int[] keyCodes) {
Editable editable = this.getText();
//獲取游標偏移量下標
int startIndex = this.getSelectionStart();
switch (primaryCode) {
case Keyboard.KEYCODE_CANCEL:// 隱藏鍵盤
hideKeyboard();
break;
case Keyboard.KEYCODE_DELETE:// 回退
if (editable != null && editable.length() > 0) {
if (startIndex > 0) {
editable.delete(startIndex - 1, startIndex);
}
}
break;
case 9994://左移
setSelection(startIndex-1);
break;
case 9995://重輸
editable.clear();
break;
case 9996://右移
if (startIndex < length()) {
setSelection(startIndex + 1);
}
break;
default:
editable.insert(startIndex, Character.toString((char) primaryCode));
break;
}
}
@Override
public void onText(CharSequence text) {
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeDown() {
}
@Override
public void swipeUp() {
}
/**
* 根據key code 獲取 Keyboard.Key 物件
* @param primaryCode
* @return
*/
private Keyboard.Key getKeyByKeyCode(int primaryCode) {
if(null != mKeyboard){
List<Keyboard.Key> keyList = mKeyboard.getKeys();
for (int i =0,size= keyList.size(); i < size; i++) {
Keyboard.Key key = keyList.get(i);
int codes[] = key.codes;
if(codes[0] == primaryCode){
return key;
}
}
}
return null;
}
@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);
}
@SuppressLint("MissingSuperCall")
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
if (!focused) {
hideKeyboard();
} else {
hideSysInput();
showKeyboard();
}
super.onFocusChanged(focused, direction, previouslyFocusedRect);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
this.mDecorView = ((Activity) getContext()).getWindow().getDecorView();
hideSysInput();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
hideKeyboard();
mKeyboardWindow = null;
mKeyboardView = null;
mKeyboard = null;
mDecorView = null;
}
/**
* 顯示自定義鍵盤
*/
private void showKeyboard() {
if (null != mKeyboardWindow) {
if (!mKeyboardWindow.isShowing()) {
mKeyboardView.setKeyboard(mKeyboard);
mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0);
}
}
}
/**
* 遮蔽系統輸入法
*/
private void notSystemSoftInput(){
if (Build.VERSION.SDK_INT <= 10) {
setInputType(InputType.TYPE_NULL);
} else {
((Activity)getContext()).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
try {
Class<EditText> cls = EditText.class;
Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
setShowSoftInputOnFocus.setAccessible(true);
setShowSoftInputOnFocus.invoke(this, false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 隱藏自定義鍵盤
*/
private void hideKeyboard() {
if (null != mKeyboardWindow) {
if (mKeyboardWindow.isShowing()) {
mKeyboardWindow.dismiss();
}
}
}
/**
* 隱藏系統鍵盤
*/
private void hideSysInput() {
if (this.getWindowToken() != null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
@Override
public void onClick(View v) {
requestFocus();
requestFocusFromTouch();
hideSysInput();
showKeyboard();
}
}
複製程式碼
程式碼中註釋寫的已經很清晰了,就不做一一的講解了。 #####結尾
-
該自定義元件目前只是支援了身份證鍵盤,xml下只提供了身份證鍵盤的描述檔案。如果需要其他鍵盤可以自己定義xml檔案,如果有特殊點選事件,邏輯放入
public void onKey(int primaryCode, int[] keyCodes)
case 相應的keycode邏輯下即可。 -
程式碼已放入github https://github.com/zyl409214686/CustomKeyboardView,歡迎提 issues、star、Fork。
-
效果圖:
參考: