概述
在項目開發中遇到一個需求,”只要數字鍵盤的輸入,僅僅有大寫字母的輸入,某些輸入法總是會提示更新,彈出廣告等“,使得我們需要自定義輸入。
關聯到的知識
- KeyboardView 一個視圖對象,展示了鍵盤。它需要關聯到一個 Keyboard對象才能展示。
- Keyboard 鍵盤對象,通過加載xml的配置獲得鍵盤的排列。
- xml 文件鍵盤描述 一個xml文件,放置在 xml 資源文件夾下,描述了 顯示的鍵盤按鈕,和排列,鍵盤寬度和高度等。
具體實現
准備xml鍵盤描述文件
在xml文件夾下創建文件,下面的代碼中使用 “ 33%p” 這樣的單位指定一定的 百分比,以適配屏幕,詳細內容如下:
<?xml version="1.0" encoding="UTF-8"?><!-- 數字鍵盤 --> <Keyboard xmlns:android="http://schemas.android.com/apk/res/android" android:horizontalGap="0dp" android:keyHeight="61dp" android:keyWidth="33%p" android:verticalGap="0dp"> <Row> <Key android:codes="49" android:keyEdgeFlags="left" android:keyLabel="1" /> <Key android:codes="50" android:keyLabel="2" /> <Key android:codes="51" android:keyLabel="3" /> </Row> <Row> <Key android:codes="52" android:keyEdgeFlags="left" android:keyLabel="4" /> <Key android:codes="53" android:keyLabel="5" /> <Key android:codes="54" android:keyLabel="6" /> </Row> <Row> <Key android:codes="55" android:keyEdgeFlags="left" android:keyLabel="7" /> <Key android:codes="56" android:keyLabel="8" /> <Key android:codes="57" android:keyLabel="9" /> </Row> <Row> <Key android:codes="48" android:keyEdgeFlags="left" android:keyLabel="0" /> <Key android:codes="-5" android:isRepeatable="true" android:keyIcon="@drawable/keyboard_delete" android:keyWidth="66%p" /> </Row> </Keyboard>
創建Keyboard對象
要先配置好xml文件,在構造方法里傳入上面的xml文件
this.keyboard = new Keyboard(mActivity, R.xml.small_keyboard);
構造KeyboardView
keyboardView 對象可以在 xml 中描述,類似下面這樣
<android.inputmethodservice.KeyboardView android:id="@+id/keyboard_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@android:color/transparent" android:focusable="true" android:focusableInTouchMode="true" android:keyBackground="@drawable/keyboard_key" android:keyTextColor="@color/white" android:keyTextSize="@dimen/sp_32" android:visibility="visible" />
獲得 KeyboardView並進行配置,需要關聯到具體的 keyboard 對象
KeyboardView keyboardView = (KeyboardView) viewContainer.findViewById(R.id.keyboard_view); this.keyboardView = keyboardView; this.keyboardView.setKeyboard(keyboard); this.keyboardView.setEnabled(true); this.keyboardView.setPreviewEnabled(false); this.keyboardView.setOnKeyboardActionListener(listener2);
隱藏系統自帶的鍵盤
根據android系統的版本的不同,有不同的方法,需要利用反射,見代碼:
/** * 隱藏系統鍵盤 * * @param editText */ public static void hideSystemSofeKeyboard(EditText editText) { int sdkInt = Build.VERSION.SDK_INT; if (sdkInt >= 11) { try { Class<EditText> cls = EditText.class; Method setShowSoftInputOnFocus; setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class); setShowSoftInputOnFocus.setAccessible(true); setShowSoftInputOnFocus.invoke(editText, false); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } else { editText.setInputType(InputType.TYPE_NULL); } }
從底部彈出鍵盤
輸入法需要從頁面底部向上彈出,需要一個過渡動畫,android每個頁面都有一個window,window包含了一個getDecorView 根視圖,我們要把鍵盤的視圖添加到這個根視圖下,配合動畫出現鍵盤。
public void showSoftKeyboard() { if (viewContainer == null) { viewContainer = mActivity.getLayoutInflater().inflate(R.layout.keyboardview_layout, null); } else { if (viewContainer.getParent() != null) return; } FrameLayout frameLayout = (FrameLayout) mActivity.getWindow().getDecorView(); KeyboardView keyboardView = (KeyboardView) viewContainer.findViewById(R.id.keyboard_view); this.keyboardView = keyboardView; this.keyboardView.setKeyboard(keyboard); this.keyboardView.setEnabled(true); this.keyboardView.setPreviewEnabled(false); this.keyboardView.setOnKeyboardActionListener(listener2); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.BOTTOM; frameLayout.addView(viewContainer, lp); //viewContainer.setVisibility(View.GONE); viewContainer.setAnimation(AnimationUtils.loadAnimation(mActivity, R.anim.down_to_up)); }
完整的代碼如下:
package vir56k.democustomkeyboard; import android.app.Activity; import android.inputmethodservice.Keyboard; import android.inputmethodservice.KeyboardView; import android.inputmethodservice.KeyboardView.OnKeyboardActionListener; import android.os.Build; import android.text.Editable; import android.text.InputType; import android.text.TextUtils; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.animation.AnimationUtils; import android.widget.EditText; import android.widget.FrameLayout; import java.lang.reflect.Method; public class PopupKeyboardUtil { private Activity mActivity; private KeyboardView keyboardView; private Keyboard keyboard;// 全鍵盤包括數字和字母 private EditText editText1; public PopupKeyboardUtil(Activity mActivity) { this.mActivity = mActivity; this.keyboard = new Keyboard(mActivity, R.xml.small_keyboard); } public void attachTo(EditText editText, boolean isAuto) { this.editText1 = editText; hideSystemSofeKeyboard(this.editText1); setAutoShowOnFocs(isAuto); } public void setAutoShowOnFocs(boolean enable) { if (editText1 == null) return; if (enable) editText1.setOnFocusChangeListener(onFocusChangeListener1); else editText1.setOnFocusChangeListener(null); } View.OnFocusChangeListener onFocusChangeListener1 = new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) showSoftKeyboard(); else hideSoftKeyboard(); } }; View viewContainer; public void showSoftKeyboard() { if (viewContainer == null) { viewContainer = mActivity.getLayoutInflater().inflate(R.layout.keyboardview_layout, null); } else { if (viewContainer.getParent() != null) return; } FrameLayout frameLayout = (FrameLayout) mActivity.getWindow().getDecorView(); KeyboardView keyboardView = (KeyboardView) viewContainer.findViewById(R.id.keyboard_view); this.keyboardView = keyboardView; this.keyboardView.setKeyboard(keyboard); this.keyboardView.setEnabled(true); this.keyboardView.setPreviewEnabled(false); this.keyboardView.setOnKeyboardActionListener(listener2); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT); lp.gravity = Gravity.BOTTOM; frameLayout.addView(viewContainer, lp); //viewContainer.setVisibility(View.GONE); viewContainer.setAnimation(AnimationUtils.loadAnimation(mActivity, R.anim.down_to_up)); } public void hideSoftKeyboard() { if (viewContainer != null && viewContainer.getParent() != null) { ((ViewGroup) viewContainer.getParent()).removeView(viewContainer); } } public boolean isShowing() { if (viewContainer == null) return false; return viewContainer.getVisibility() == View.VISIBLE; } /** * 隱藏系統鍵盤 * * @param editText */ public static void hideSystemSofeKeyboard(EditText editText) { int sdkInt = Build.VERSION.SDK_INT; if (sdkInt >= 11) { try { Class<EditText> cls = EditText.class; Method setShowSoftInputOnFocus; setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class); setShowSoftInputOnFocus.setAccessible(true); setShowSoftInputOnFocus.invoke(editText, false); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } else { editText.setInputType(InputType.TYPE_NULL); } } private OnKeyboardActionListener listener2 = new 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) { } @Override public void onKey(int primaryCode, int[] keyCodes) { if (editText1 != null) { keyCode_delect(primaryCode, editText1); } keyboardView.postInvalidate(); } }; /** * 判斷回退鍵 和大小寫切換 * * @param primaryCode * @param edText */ private void keyCode_delect(int primaryCode, EditText edText) { Editable editable = edText.getText(); int start = edText.getSelectionStart(); if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退 if (edText.hasFocus()) { if (!TextUtils.isEmpty(editable)) { if (start > 0) { editable.delete(start - 1, start); } } } } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小寫切換 keyboardView.setKeyboard(keyboard); } else { if (edText.hasFocus()) { editable.insert(start, Character.toString((char) primaryCode)); } } } }
功能完成后,具體調用的演示:
package vir56k.democustomkeyboard; import android.app.Activity; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; public class MainActivity extends AppCompatActivity { EditText edittext1; PopupKeyboardUtil smallKeyboardUtil; private View viewContainer; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); edittext1 = (EditText) findViewById(R.id.edittext1); smallKeyboardUtil = new PopupKeyboardUtil(self()); smallKeyboardUtil.attachTo(edittext1, false); //smallKeyboardUtil.setAutoShowOnFocs(false); } public void onClickView(View view) { if (view.getId() == R.id.btn1) smallKeyboardUtil.showSoftKeyboard(); if (view.getId() == R.id.btn2) smallKeyboardUtil.hideSoftKeyboard(); } private Activity self() { return this; } }
完整的代碼下載:
https://github.com/vir56k/demo/tree/master/demo.customkeyboard