1. 程式人生 > >Android自定義軟鍵盤KeyboardView 使用例項

Android自定義軟鍵盤KeyboardView 使用例項

在有些應用中會有定製軟鍵盤的需求,往往實現起來會有些難度,或者說實現出來的效果不盡如人意。
最近在專案中有這種需求
這裡寫圖片描述
博主也是不辱使命地完成了這個需求,效果圖如下
這裡寫圖片描述
說一下思路的和詳細實現

主要是利用android自帶的android.inputmethodservice.KeyboardView
對它進行自定義。

首先在res/目錄下新建一個xml資料夾,新建一個xml檔案

number.xml

<?xml version="1.0" encoding="utf-8"?>  
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
android:keyWidth="33.33333%p" android:horizontalGap="1dp" android:verticalGap="1dp" android:keyHeight="10%p">
<Row> <Key android:codes="55" android:keyLabel="7" /> <Key android:codes="56" android:keyLabel="8" /> <Key
android:codes="57" android:keyLabel="9" android:keyEdgeFlags="right"/>
</Row> <Row> <Key android:codes="52" android:keyLabel="4" /> <Key android:codes="53" android:keyLabel="5" /> <Key android:codes="54"
android:keyLabel="6" android:keyEdgeFlags="right"/>
</Row> <Row> <Key android:codes="49" android:keyLabel="1" /> <Key android:codes="50" android:keyLabel="2" /> <Key android:codes="51" android:keyLabel="3" android:keyEdgeFlags="right"/> </Row> <Row> <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="-3" android:keyEdgeFlags="right" android:keyIcon="@drawable/resale_btn_key_ok"/> --> </Row> </Keyboard>

鍵盤工具類
KeyboardUtil.java

public class KeyboardUtil {
    private Context ctx;
    private MyKeyboardView keyboardView;
    private Keyboard k1;// 鍵盤
//  private Keyboard k2;
//  private Keyboard k3;
    public boolean isnun = false;// 是否資料鍵盤
    public boolean isupper = false;// 是否大寫
    public final static int TYPE_NUMBER = 1; // 數量
    public final static int TYPE_PRICE = 2; // 價格
    private int type = -1;
    private KeyboardListener keyboardListener;

    private EditText ed;

    public interface KeyboardListener {
        void onOK();
    }

    /**
     * @param ctx
     * @param parent    包含MyKeyboardView的ViewGroup
     * @param edit
     */
    public KeyboardUtil(Context ctx, View parent, EditText edit) {
        this.ctx = ctx;
        this.ed = edit;
        //此處可替換鍵盤xml
        k1 = new Keyboard(ctx, R.xml.number);
        keyboardView = (MyKeyboardView) parent.findViewById(R.id.keyboard_view);
        keyboardView.setContext(ctx);
        keyboardView.setKeyboard(k1);
        keyboardView.setEnabled(true);
        keyboardView.setPreviewEnabled(true);
        keyboardView.setOnKeyboardActionListener(listener);
    }

    /**
     * @param ctx   必須要用Activity例項作為上下文傳入
     * @param edit
     */
    public KeyboardUtil(Context ctx, EditText edit) {
        this.ctx = ctx;
        this.ed = edit;
        //此處可替換鍵盤xml
        k1 = new Keyboard(ctx, R.xml.number);
        try {
            keyboardView = (MyKeyboardView) ((Activity)ctx).findViewById(R.id.keyboard_view);
            keyboardView.setContext(ctx);
            keyboardView.setKeyboard(k1);
            keyboardView.setEnabled(true);
            keyboardView.setPreviewEnabled(true);
            keyboardView.setOnKeyboardActionListener(listener);
        } catch (Exception e) {
            Log.e("keyboardView", "keyboardView init failed!");
        }
    }

    public void setKeyboardListener(KeyboardListener keyboardListener) {
        this.keyboardListener = keyboardListener;
    }

    public void setType(int typein) {
        type = typein;
    }

    private OnKeyboardActionListener listener = 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) {
            Editable editable = ed.getText();
            int start = ed.getSelectionStart();
            if (primaryCode == Keyboard.KEYCODE_CANCEL) {// 完成
                // hideKeyboard();
                keyboardListener.onOK();
            } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
                if (editable != null && editable.length() > 0) {
                    if (start > 0) {
                        editable.delete(start - 1, start);
                    }
                }
            } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小寫切換
                changeKey();
                keyboardView.setKeyboard(k1);

            } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {// 鍵盤切換
                if (isnun) {
                    isnun = false;
                    keyboardView.setKeyboard(k1);
                } else {
                    isnun = true;
//                  keyboardView.setKeyboard(k2);
                }
            } else if (primaryCode == 57419) { // go left
                if (start > 0) {
                    ed.setSelection(start - 1);
                }
            } else if (primaryCode == 57421) { // go right
                if (start < ed.length()) {
                    ed.setSelection(start + 1);
                }
            } else if (primaryCode == 46) {    // 小數點
                String text = ed.getText().toString();
                if (type == TYPE_PRICE) {
                    if (!ed.getText().toString().contains(".") && text.length() <= 7) {
                        editable.insert(start,
                                Character.toString((char) primaryCode));
                    }
                }
            } else {
                String text = ed.getText().toString();
                switch (type) {
                case TYPE_NUMBER:
                    if (text.length() < 7) {
                        editable.insert(start,
                                Character.toString((char) primaryCode));
                    }
                    break;

                case TYPE_PRICE:
                    if ((!text.contains(".") || text.length() - 1
                            - text.indexOf(".") <= 1)
                            && text.length() < (text.contains(".")?10:7)) {
                        //小數點後最長2位,接受7位整數
                        editable.insert(start,
                                Character.toString((char) primaryCode));
                    }
                    break;
                default:
                    editable.insert(start,
                            Character.toString((char) primaryCode));
                    break;
                }

            }
        }
    };

    /**
     * 鍵盤大小寫切換
     */
    private void changeKey() {
        List<Key> keylist = k1.getKeys();
        if (isupper) {// 大寫切換小寫
            isupper = false;
            for (Key key : keylist) {
                if (key.label != null && isword(key.label.toString())) {
                    key.label = key.label.toString().toLowerCase();
                    key.codes[0] = key.codes[0] + 32;
                }
            }
        } else {// 小寫切換大寫
            isupper = true;
            for (Key key : keylist) {
                if (key.label != null && isword(key.label.toString())) {
                    key.label = key.label.toString().toUpperCase();
                    key.codes[0] = key.codes[0] - 32;
                }
            }
        }
    }

    public void showKeyboard() {
        int visibility = keyboardView.getVisibility();
        if (visibility == View.GONE || visibility == View.INVISIBLE) {
            keyboardView.setVisibility(View.VISIBLE);
        }
    }

    public void hideKeyboard() {
        int visibility = keyboardView.getVisibility();
        if (visibility == View.VISIBLE) {
            keyboardView.setVisibility(View.INVISIBLE);
        }
    }

    private boolean isword(String str) {
        String wordstr = "abcdefghijklmnopqrstuvwxyz";
        if (wordstr.indexOf(str.toLowerCase()) > -1) {
            return true;
        }
        return false;
    }
}

鍵盤介面佈局

    <RelativeLayout
        android:id="@+id/rl__keyboard"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@null"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:visibility="gone" >

        <com.ysdemo.keyboard.view.MyKeyboardView
            android:id="@+id/keyboard_view"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:background="#d8d8d8"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:keyBackground="@drawable/bg_keyboard_btn"
            android:keyPreviewLayout="@layout/preview_keyboard"
            android:keyTextColor="#333333"
            android:paddingTop="1dp"
            android:shadowColor="#ffffff"
            android:shadowRadius="0.0" />

        <RelativeLayout
            android:id="@+id/rl_editor"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_above="@id/keyboard_view"
            android:background="#ffffff"
            android:gravity="center"
            android:padding="3dp" >

            <com.ysdemo.keyboard.view.XEditText
                android:id="@+id/et_amount"
                android:layout_width="match_parent"
                android:layout_height="60dp"
                android:layout_alignParentTop="true"
                android:layout_margin="2dp"
                android:background="#ffffff"
                android:drawableRight="@drawable/keboard_back"
                android:gravity="center"
                android:inputType="@null"
                android:padding="3dp"
                android:textColor="#00aeef" />
        </RelativeLayout>
    </RelativeLayout>

在Activity中初始化鍵盤,實際使用時可以在基類Activity中做這些

public class MainActivity extends Activity {
    private RelativeLayout rl_keyboard;
    private KeyboardUtil keyboardUtil;
    private int change_type;
    private XEditText et_amount;
    private Button btn_showKey,btn_hideKey,btn_price,btn_number;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initTestBtn();
        initKeyboard();
    }

    private void initTestBtn() {
        btn_showKey = (Button) findViewById(R.id.btn_showKey);
        btn_hideKey = (Button) findViewById(R.id.btn_hideKey);
        btn_price = (Button) findViewById(R.id.btn_price);
        btn_number = (Button) findViewById(R.id.btn_number);
        btn_showKey.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                showKeyBoard();
            }
        });
        btn_hideKey.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                hideKeyBoard();
            }
        });
        btn_price.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                change_type = KeyboardUtil.TYPE_PRICE;
                showKeyBoard();
            }
        });
        btn_number.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                change_type = KeyboardUtil.TYPE_NUMBER;
                showKeyBoard();
            }
        });
    }

    private void initKeyboard() {
        et_amount = (XEditText) findViewById(R.id.et_amount);
        keyboardUtil = new KeyboardUtil(this, et_amount);
        rl_keyboard = (RelativeLayout) findViewById(R.id.rl__keyboard);
        et_amount.setInputType(InputType.TYPE_NULL);
        keyboardUtil.setKeyboardListener(new KeyboardListener() {

            @Override
            public void onOK() {
                String result = et_amount.getText().toString();
                String msg = "";
                if (!TextUtils.isEmpty(result)) {
                    switch (change_type) {
                    case KeyboardUtil.TYPE_NUMBER:
                        msg += "num:"+result;
                        break;
                    case KeyboardUtil.TYPE_PRICE:
                        msg += "price:"+result;
                        break;
                    default:
                        msg += "input:"+result;
                        break;
                    }
                    Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
                }
                hideKeyBoard();
                change_type = -1;
            }
        });
        et_amount.setDrawableRightListener(new DrawableRightListener() {

            @Override
            public void onDrawableRightClick(View view) {
                Editable editable = ((EditText)view).getText();
                int start = ((EditText)view).getSelectionStart();
                if (editable != null && editable.length() > 0) {
                    if (start > 0) {
                        editable.delete(start - 1, start);
                    }
                }
            }
        });
    }
    /**
     * 顯示鍵盤
     */
    protected void showKeyBoard() {
        rl_keyboard.setVisibility(View.VISIBLE);
        et_amount.setText("");
        switch (change_type) {
        case KeyboardUtil.TYPE_NUMBER:
            et_amount.setHint("請輸入數量");
            break;

        case KeyboardUtil.TYPE_PRICE:
            et_amount.setHint("請輸入價格");
            break;

        default:
            break;
        }
        keyboardUtil.setType(change_type);
        keyboardUtil.showKeyboard();
    }

    /**
     * 顯示鍵盤
     */
    protected void hideKeyBoard() {
        rl_keyboard.setVisibility(View.GONE);
        keyboardUtil.hideKeyboard();
        keyboardUtil.setType(-1);
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (rl_keyboard.getVisibility() != View.GONE) {
                hideKeyBoard();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }
}

其他微調與細節:
1.設計給的退格鍵在鍵盤外 是單獨實現的。
2.OK鍵的顏色不一致,由於沒有直接修改鍵盤按鍵背景的方法,我重寫了KeyboardView的Ondraw方法。
3.xml裡code儘量使用android原始碼中的定義過的。
4.博文寫的有些倉促,註釋和說明也不怎麼詳細,整個封裝的也不太好用,大家見諒。如有能力,歡迎申請pull、fork。

demo下載地址
csdn
github