Android自定義鍵盤(pán):數(shù)字鍵盤(pán)和字母鍵盤(pán)

在項(xiàng)目中,產(chǎn)品對(duì)于輸入方式會(huì)有特殊的要求,需要對(duì)輸入方式增加特定的限制,這就需要采用自定義鍵盤(pán)。本文主要講述數(shù)字鍵盤(pán)和字母鍵盤(pán)的自定義實(shí)現(xiàn)。

項(xiàng)目地址:https://github.com/xudjx/djkeyboard
鍵盤(pán)效果:

自定義鍵盤(pán)的實(shí)現(xiàn)步驟如下:

  1. 自定義CustomKeyboard, 繼承自系統(tǒng)Keyboard,實(shí)現(xiàn)KeyboardView.OnKeyboardActionListener相關(guān)接口,以處理用戶的點(diǎn)擊回調(diào);
  2. 自定義CustomKeyboardView, 繼承自KeyboardView,實(shí)現(xiàn)自定義鍵盤(pán)繪制;
  3. 創(chuàng)建KeyboardManager, 用于處理自定義鍵盤(pán)的顯示以及和輸入U(xiǎn)I的交互

自定義CustomKeyboard

Android系統(tǒng)Keyboard的構(gòu)造方法如下:

 /**
     * Creates a keyboard from the given xml key layout file.
     * @param context the application or service context
     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
     */
    public Keyboard(Context context, int xmlLayoutResId) {
        this(context, xmlLayoutResId, 0);
    }

    /**
     * Creates a keyboard from the given xml key layout file. Weeds out rows
     * that have a keyboard mode defined but don't match the specified mode.
     * @param context the application or service context
     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
     * @param modeId keyboard mode identifier
     * @param width sets width of keyboard
     * @param height sets height of keyboard
     */
    public Keyboard(Context context, @XmlRes int xmlLayoutResId, int modeId, int width,
            int height) {
            ...
    }
    等等

其中,參數(shù)xmlLayoutResId是必須的,另外還可以通過(guò)計(jì)算系統(tǒng)鍵盤(pán)的高度來(lái)設(shè)定自定義鍵盤(pán)的高度。
xmlLayoutRes的格式如下:

<?xml version="1.0" encoding="UTF-8"?>
<Keyboard android:keyWidth="24.9%p"
          android:keyHeight="49dp"
          android:horizontalGap="0.1333%p"
          android:verticalGap="1px"
          xmlns:android="http://schemas.android.com/apk/res/android">
    <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" />
        <Key android:codes="-5" android:iconPreview="@drawable/key_num_del_bg"
             android:isRepeatable="true"/>
    </Row>
    ...
</Keyboard>

詳細(xì)的數(shù)字鍵盤(pán)和字母鍵盤(pán)xmlLayoutRes資源文件可以從以下鏈接獲取:
數(shù)字鍵盤(pán)xmlLayoutRes
字母鍵盤(pán)xmlLayoutRes

CustomKeyboard主要目的就是賦予xmlLayoutRes并實(shí)現(xiàn)特定按鍵的點(diǎn)擊處理,其主要重載的方法是onKey(int primaryCode, int[] keyCodes)。詳細(xì)代碼如下:

public abstract class BaseKeyboard extends Keyboard implements KeyboardView.OnKeyboardActionListener{

  @Override
  public void onKey(int primaryCode, int[] keyCodes) {
        if(null != mEditText && mEditText.hasFocus() && !handleSpecialKey(primaryCode)) {
            Editable editable = mEditText.getText();
            int start = mEditText.getSelectionStart();
            int end = mEditText.getSelectionEnd();
            if (end > start){
                editable.delete(start,end);
            }
            if(primaryCode == KEYCODE_DELETE) {
                if(!TextUtils.isEmpty(editable)) {
                    if(start > 0) {
                        editable.delete(start-1,start);
                    }
                }
            }else if(primaryCode == getKeyCode(R.integer.hide_keyboard)){
                hideKeyboard();
            }else {
                editable.insert(start,Character.toString((char) primaryCode));
            }
        }
    }

  public abstract boolean handleSpecialKey(int primaryCode);
}

如上所示是BaseKeyboard,數(shù)字鍵盤(pán)和字母鍵盤(pán)需要繼承它,并實(shí)現(xiàn)public abstract boolean handleSpecialKey(int primaryCode)方法。

自定義CustomKeyboardView

KeyboardView 是承載不同的keyboard并繪制keyboard, 是鍵盤(pán)布局的繪制板, 并與系統(tǒng)交互。通過(guò)繼承KeyboardView自定義CustomKeyboardView,可以對(duì)按鍵樣式實(shí)現(xiàn)自定義。考察KeyboardView的源碼,發(fā)現(xiàn)其UI樣式都是private類(lèi)型,這就需要通過(guò)反射的方式獲取特定的UI屬性,并重新進(jìn)行賦值,同時(shí)重載onDraw()方法,在onDraw()中重新繪制。

詳細(xì)代碼可以參考github源碼: BaseKeyBoardView源碼

自定義鍵盤(pán)的UI效果如下:

數(shù)字鍵盤(pán)

字母鍵盤(pán)

創(chuàng)建KeyboardManager

主要處理以下功能邏輯:

  1. 綁定EditText和Keyboard,監(jiān)聽(tīng)EditText的OnFocusChangeListener,處理鍵盤(pán)彈出和鍵盤(pán)掩藏;
  2. 處理系統(tǒng)鍵盤(pán)和自定義鍵盤(pán)之間的切換關(guān)系;
  3. 處理鍵盤(pán)區(qū)域其他自定義view的顯示,比如需要讓鍵盤(pán)自動(dòng)搜索功能時(shí),可在manager中進(jìn)行相關(guān)處理

以綁定EditText為例:

public void bindToEditor(EditText editText, BaseKeyboard keyboard) {
    hideSystemSoftKeyboard(editText);
    editText.setTag(R.id.bind_keyboard_2_editor, keyboard);
    if (keyboard.getKeyStyle() == null) {
        keyboard.setKeyStyle(mDefaultKeyStyle);
    }
    editText.setOnFocusChangeListener(editorFocusChangeListener);
}

private final View.OnFocusChangeListener editorFocusChangeListener = new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(final View v, boolean hasFocus) {
        if (v instanceof EditText) {
            if (hasFocus) {
              v.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        showSoftKeyboard((EditText) v);
                    }
                },300);
            } else {
                hideSoftKeyboard();
            }
        }
    }
};

public void showSoftKeyboard(EditText editText) {
    mRootView.addOnLayoutChangeListener(mOnLayoutChangeListener);
    BaseKeyboard keyboard = getBindKeyboard(editText);
    if (keyboard == null) {
        Log.e(TAG, "edit text not bind to keyboard");
        return;
    }
    keyboard.setEditText(editText);
    keyboard.setNextFocusView(mKeyboardWithSearchView.getEditText());
    initKeyboard(keyboard);
    ...
}

鍵盤(pán)的使用方式非常簡(jiǎn)單, 通過(guò)KeyboardManager實(shí)現(xiàn)調(diào)用

數(shù)字鍵盤(pán):

KeyboardManager keyboardManagerNumber = new KeyboardManager(this);
keyboardManagerNumber.bindToEditor(editText2, new NumberKeyboard(context,NumberKeyboard.DEFAULT_NUMBER_XML_LAYOUT));

字母鍵盤(pán):

KeyboardManager keyboardManagerAbc = new KeyboardManager(this);
keyboardManagerAbc.bindToEditor(editText1, new ABCKeyboard(context, ABCKeyboard.DEFAULT_ABC_XML_LAYOUT));

至此,自定義鍵盤(pán)的實(shí)現(xiàn)就介紹完了,文中介紹的更多還是實(shí)現(xiàn)的思路,具體實(shí)現(xiàn)可以參考github,有需要的用戶也可以直接修改項(xiàng)目的源碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 178,741評(píng)論 25 709
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點(diǎn)贊按鈕進(jìn)度條TabLayout圖標(biāo)下拉刷新...
    皇小弟閱讀 47,133評(píng)論 22 665
  • 原文鏈接:https://github.com/opendigg/awesome-github-android-u...
    IM魂影閱讀 33,143評(píng)論 6 472
  • 文 / 葉子 我是60后。小時(shí)候雖然家里困難,但每到端午節(jié)都很開(kāi)心。 節(jié)前的一兩天,媽媽就開(kāi)始包粽子,煮粽子。到了...
    幫得上閱讀 528評(píng)論 0 1
  • 最近,有人在某知名雜志上憂郁地宣稱:“世界上沒(méi)有任何東西比金錢(qián)更使人沮喪了?!蔽矣X(jué)得他可能不太會(huì)花錢(qián)。研究顯示,如...
    春師閱讀 374評(píng)論 0 0

友情鏈接更多精彩內(nèi)容