自定義軟鍵盤(屏蔽系統輸入法,隨機鍵盤)


實現思路:
1.自定義RandomKeyboard,繼承系統keyboard
2.自定義keyboardViewGroup(線性佈局,含一級子控件NestedScrollView和自定義RandomKeyboard),重新addview方法使添加的子控件添加到NestedScrollView裏。可在這個控件初始化時屏蔽系統輸入法,監聽事件分發通過scrollview中findFocus獲取當前有焦點的edittext控件並綁定RandomKeyboard

核心代碼

RandomKeyboard

  • 鍵盤操作
 public void onKey(int primaryCode, int[] keyCodes) {
        Editable editable = null;
        int selectionStart = 0;
        if (editText != null) {
            editable = editText.getText();
            selectionStart = editText.getSelectionStart();
        }
        if (keyboard != null) {
            switch (primaryCode) {
                case Keyboard.KEYCODE_SHIFT://shift處理 大小寫字母切換
                    keyboard.setShifted(!keyboard.isShifted());
                    invalidateAllKeys();
                    break;
                case Keyboard.KEYCODE_DELETE://刪除處理
                    if (editable != null && editable.length() > 0 && selectionStart > 0) {
                        editable.delete(selectionStart - 1, selectionStart);
                    }
                    break;
                   
              ....
              自定義鍵盤操作
              ....
              
                case ENTER_KEYBOARD://enter處理
                    if (editText != null && editText.getImeOptions() == EditorInfo.IME_ACTION_NEXT) {
                        @SuppressLint("WrongConstant") View view = editText.focusSearch(FOCUS_FORWARD);
                        editText.onEditorAction(EditorInfo.IME_ACTION_NEXT);
                        if (view instanceof EditText) {
                            bindEditText((EditText) view);
                        }
                    } else {
                        if (editText != null && editText.hasFocus()) {
                            editText.clearFocus();
                        }
                        hide();
                    }
                    break;
                default:
                    if (primaryCode >= 97 && primaryCode <= 97 + 26) {
                        if (editText != null) {
                            editable.insert(selectionStart,
                                    keyboard.isShifted() ? Character.toString((char) (primaryCode - 32))
                                            : Character.toString((char) primaryCode));
                        }
                    } else {
                        if (editable != null) {
                            editable.insert(
                                    selectionStart,
                                    Character.toString((char) primaryCode));
                        }
                    }
                    break;
            }
        }
    }

  • 隨機打亂key
 private RandomKeyboard setRandom() {
        if (keyType == TYPE_SYMBOL || keyType == TYPE_LETTER_AND_NUM) {
            return this;
        }
        if (keyboard != null) {
            List<Keyboard.Key> newKeys = keyboard.getKeys();
            if (checkList(newKeys)) {
                containerKeys.clear();
                resultKeys.clear();
                //篩選並緩存可隨機的key
                for (Keyboard.Key key : newKeys) {
                    if (key != null && isNeedRandom(key.label)) {
                        containerKeys.add(new KeyModel(key.codes, key.label));
                    }
                }
                //隨機打亂篩選出的key
                Random rand = new SecureRandom();
//                rand.setSeed(SystemClock.currentThreadTimeMillis());
                int size = containerKeys.size();
                for (int i = 0; i < size; i++) {
                    int num = rand.nextInt(size - i);
                    resultKeys.add(containerKeys.get(num));
                    containerKeys.remove(num);
                }
                //將打亂的key賦值給鍵盤空位(第一步中取值的位置)
                int count = 0;
                for (Keyboard.Key key : newKeys) {
                    if (key != null && isNeedRandom(key.label) && checkListItem(resultKeys, count)) {
                        KeyModel randomKey = resultKeys.get(count);
                        key.label = randomKey.getLable();
                        key.codes = randomKey.getCodes();
                        count++;
                    }
                }
                invalidateAllKeys();
                isRandom = true;
            }
        }
        return this;
    }

RandomKeyboardViewGroup

  • 禁用系統輸入法
 //禁用系統輸入法
        if (context instanceof Activity) {
            Window window = ((Activity) context).getWindow();
            ((Activity) context).getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }
  • 自動查找綁定EditText
   @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean touchEvent = super.dispatchTouchEvent(ev);
        View editFocus = findEditFocus();
        if (keyboard != null) {
            if (editFocus != null) {
                if (ViewUtils.isOutsideTheView(editFocus, ev) && ViewUtils.isOutsideTheView(keyboard, ev)) {
                    editFocus.clearFocus();
                    keyboard.hide();
                } else {
                    keyboard.bindEditText((EditText) editFocus);
                    keyboard.show();
                }
            } else {
                keyboard.hide();
            }
        }
        return touchEvent;
    }

    public View findEditFocus() {
        View currentFocus = slContent != null ? slContent.findFocus() : null;
        return currentFocus instanceof EditText ? currentFocus : null;
    }

自定義RandomKeyboard

繼承自KeyboardView
實現OnKeyboardActionListener監聽
重寫 public void onKey(int primaryCode, int[] keyCodes) 方法控制軟鍵盤操作

public class RandomKeyboard extends KeyboardView implements KeyboardView.OnKeyboardActionListener, LifecycleObserver {

    private static final int LETTER_KEYBOARD = -10;
    private static final int NUMBER_KEYBOARD = -11;
    private static final int SYMBOL_KEYBOARD = -12;
    private static final int ENTER_KEYBOARD = -13;

    private Context context;
    private Keyboard keyboard;
    private EditText editText;

    private boolean isRandom = false;
    private boolean isNeedRandom = false;
    private int keyType;
    private int defLetterType = TYPE_LETTER;
    private int defNumberType = TYPE_NUMBER;

    private List<KeyModel> containerKeys = new ArrayList<>();
    private List<KeyModel> resultKeys = new ArrayList<>();

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        if (containerKeys instanceof ArrayList) {
            containerKeys.clear();
            containerKeys = null;
        }
        if (resultKeys instanceof ArrayList) {
            resultKeys.clear();
            resultKeys = null;
        }
        containerKeys = null;
        resultKeys = null;
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().removeObserver(this);
        }
        context = null;
        editText = null;
    }

    public RandomKeyboard(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RandomKeyboard(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().addObserver(this);
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RandomKeyboard);
        isNeedRandom = typedArray.getBoolean(R.styleable.RandomKeyboard_isRandom, false);
        int anInt = typedArray.getInt(R.styleable.RandomKeyboard_keyboardType, TYPE_LETTER);
        typedArray.recycle();
        setKeyboard(anInt);
        setOnKeyboardActionListener(this);
        hide();
    }

    /**
     * 綁定EditText
     */
    public RandomKeyboard bindEditText(EditText editText) {
        this.editText = editText;
        if (editText != null) {
            setVisibility(editText.hasFocus() ? VISIBLE : GONE);
            int imeOptions = editText.getImeOptions();
            List<Keyboard.Key> keys = CheckValueUtils.checkNotNull(keyboard).getKeys();
            for (int i = 0; i < checkList(keys, "").size(); i++) {
                Keyboard.Key key = keys.get(i);
                if (key.codes[0] == -13) {
                    key.label = imeOptions == EditorInfo.IME_ACTION_NEXT ? "下一步" : "完成";
                    invalidateKey(i);
                    return this;
                }
            }
        }
        return this;
    }

    /**
     * @see Constant.KEYBOARD_TYPE
     */
    public RandomKeyboard setKeyboard(@KeyboardType int type) {
        keyType = type;
        switch (type) {
            case TYPE_LETTER:
                defLetterType = TYPE_LETTER;
                keyboard = new Keyboard(context, R.xml.letter_keyboard_layout);
                break;
            case TYPE_NUMBER:
                defNumberType = TYPE_NUMBER;
                keyboard = new Keyboard(context, R.xml.number_keyboard_layout);
                break;
            case TYPE_SYMBOL:
                keyboard = new Keyboard(context, R.xml.symbol_keyboard_layout);
                break;
            case TYPE_LETTER_AND_NUM:
                defLetterType = TYPE_LETTER_AND_NUM;
                keyboard = new Keyboard(context, R.xml.letter_num_keyboard_layout);
                break;
            case TYPE_NUM_AND_SYMBOL:
                defNumberType = TYPE_NUM_AND_SYMBOL;
                keyboard = new Keyboard(context, R.xml.num_symbol_keyboard_layout);
                break;
            default:
                keyboard = new Keyboard(context, R.xml.letter_keyboard_layout);
                break;
        }
        setKeyboard(keyboard);
        isRandom(isNeedRandom);
        return this;
    }

    public Keyboard getKeyboard() {
        return keyboard;
    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {
        Editable editable = null;
        int selectionStart = 0;
        if (editText != null) {
            editable = editText.getText();
            selectionStart = editText.getSelectionStart();
        }
        if (keyboard != null) {
            switch (primaryCode) {
                case Keyboard.KEYCODE_SHIFT://shift處理 大小寫字母切換
                    keyboard.setShifted(!keyboard.isShifted());
                    invalidateAllKeys();
                    break;
                case Keyboard.KEYCODE_DELETE://刪除處理
                    if (editable != null && editable.length() > 0 && selectionStart > 0) {
                        editable.delete(selectionStart - 1, selectionStart);
                    }
                    break;
                case LETTER_KEYBOARD:
                    setKeyboard(defLetterType);
                    break;
                case NUMBER_KEYBOARD:
                    setKeyboard(defNumberType);
                    break;
                case SYMBOL_KEYBOARD:
                    setKeyboard(TYPE_SYMBOL);
                    break;
                case ENTER_KEYBOARD://enter處理
                    if (editText != null && editText.getImeOptions() == EditorInfo.IME_ACTION_NEXT) {
                        @SuppressLint("WrongConstant") View view = editText.focusSearch(FOCUS_FORWARD);
                        editText.onEditorAction(EditorInfo.IME_ACTION_NEXT);
                        if (view instanceof EditText) {
                            bindEditText((EditText) view);
                        }
                    } else {
                        if (editText != null && editText.hasFocus()) {
                            editText.clearFocus();
                        }
                        hide();
                    }
                    break;
                default:
                    if (primaryCode >= 97 && primaryCode <= 97 + 26) {
                        if (editText != null) {
                            editable.insert(selectionStart,
                                    keyboard.isShifted() ? Character.toString((char) (primaryCode - 32))
                                            : Character.toString((char) primaryCode));
                        }
                    } else {
                        if (editable != null) {
                            editable.insert(
                                    selectionStart,
                                    Character.toString((char) primaryCode));
                        }
                    }
                    break;
            }
        }
    }

    @Override
    public void onPress(int primaryCode) {

    }

    @Override
    public void onRelease(int primaryCode) {

    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }

    /**
     * @see #setKeyboard(int)
     */
    @Override
    @Deprecated
    public final void setKeyboard(Keyboard keyboard) {
        isRandom = false;
        super.setKeyboard(keyboard);
    }

    /**
     * 隨機打亂key鍵
     *
     * @see Constant.KEYBOARD_TYPE#TYPE_SYMBOL 字符模式不可用
     * @see Constant.KEYBOARD_TYPE#TYPE_LETTER_AND_NUM 字母數字模式不可用
     */
    public RandomKeyboard isRandom(boolean isRandom) {
        isNeedRandom = isRandom;
        if (this.isRandom == isRandom) {
            return this;
        }
        if (isRandom) {
            setRandom();
        } else {
            setKeyboard(keyType);
        }
        return this;
    }

    public boolean isRandom() {
        return isRandom;
    }

    /**
     * 隨機打亂key鍵
     *
     * @see Constant.KEYBOARD_TYPE#TYPE_SYMBOL 字符模式不可用
     * @see Constant.KEYBOARD_TYPE#TYPE_LETTER_AND_NUM 字母數字模式不可用
     */
    private RandomKeyboard setRandom() {
        if (keyType == TYPE_SYMBOL || keyType == TYPE_LETTER_AND_NUM) {
            return this;
        }
        if (keyboard != null) {
            List<Keyboard.Key> newKeys = keyboard.getKeys();
            if (checkList(newKeys)) {
                containerKeys.clear();
                resultKeys.clear();
                //篩選並緩存可隨機的key
                for (Keyboard.Key key : newKeys) {
                    if (key != null && isNeedRandom(key.label)) {
                        containerKeys.add(new KeyModel(key.codes, key.label));
                    }
                }
                //隨機打亂篩選出的key
                Random rand = new SecureRandom();
//                rand.setSeed(SystemClock.currentThreadTimeMillis());
                int size = containerKeys.size();
                for (int i = 0; i < size; i++) {
                    int num = rand.nextInt(size - i);
                    resultKeys.add(containerKeys.get(num));
                    containerKeys.remove(num);
                }
                //將打亂的key賦值給鍵盤空位(第一步中取值的位置)
                int count = 0;
                for (Keyboard.Key key : newKeys) {
                    if (key != null && isNeedRandom(key.label) && checkListItem(resultKeys, count)) {
                        KeyModel randomKey = resultKeys.get(count);
                        key.label = randomKey.getLable();
                        key.codes = randomKey.getCodes();
                        count++;
                    }
                }
                invalidateAllKeys();
                isRandom = true;
            }
        }
        return this;
    }

    private boolean isNeedRandom(CharSequence s) {
        return !TextUtils.isEmpty(s) && s.length() == 1 && (CheckValueUtils.isNumber(s.toString()) || CheckValueUtils.isLetter(s.toString()));
    }

    public RandomKeyboard show() {
        if (getVisibility() != VISIBLE) {
            setVisibility(VISIBLE);
        }
        return this;
    }

    public RandomKeyboard hide() {
        if (getVisibility() != GONE || getVisibility() != INVISIBLE) {
            setVisibility(GONE);
        }
        return this;
    }
}

自定義keyboardViewGroup

使用方法:在activity佈局文件中使用,位置:可做根佈局、或置於toolbar之下到根佈局底部,可假定爲NestedScrollView使用。
注意:
1、keyboardViewGroup中有且只有一個子佈局(因這裏的佈局會加載到NestedScrollView 中)。
2、無需手動綁定EditText,RandomKeyboardViewGroup 自動查找有焦點的EditText並綁定。

public class RandomKeyboardViewGroup extends FrameLayout implements LifecycleObserver {
    private Context context;
    private View inflate;
    private NestedScrollView slContent;
    private RandomKeyboard keyboard;

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        if (slContent != null) {
            slContent.removeAllViews();
            slContent = null;
        }
        inflate = null;
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().removeObserver(this);
        }
        context = null;
        if (keyboard != null) {
            keyboard.onDestroy();
            keyboard = null;
        }
    }

    public RandomKeyboardViewGroup(Context context) {
        this(context, null);
    }

    public RandomKeyboardViewGroup(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RandomKeyboardViewGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        if (context instanceof LifecycleOwner) {
            ((LifecycleOwner) context).getLifecycle().addObserver(this);
        }
        inflate = View.inflate(context, R.layout.random_keyboard_viewgroup, null);
        slContent = ViewUtils.findViewById(inflate, R.id.sl_content);
        keyboard = ViewUtils.findViewById(inflate, R.id.random_keyboard);
        addView(inflate);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RandomKeyboardViewGroup);
        boolean aBoolean = typedArray.getBoolean(R.styleable.RandomKeyboardViewGroup_isRandom, false);
        int anInt = typedArray.getInt(R.styleable.RandomKeyboardViewGroup_keyboardType, TYPE_LETTER);
        typedArray.recycle();
        isRandom(aBoolean);
        setKeyboard(anInt);
        //禁用系統輸入法
        if (context instanceof Activity) {
            Window window = ((Activity) context).getWindow();
            ((Activity) context).getWindow().setFlags(
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        boolean touchEvent = super.dispatchTouchEvent(ev);
        View editFocus = findEditFocus();
        if (keyboard != null) {
            if (editFocus != null) {
              if (ViewUtils.isOutsideTheView(editFocus, ev) && ViewUtils.isOutsideTheView(keyboard, ev)) {
                    editFocus.clearFocus();
                    keyboard.hide();
                } else {
                    keyboard.bindEditText((EditText) editFocus);
                    keyboard.show();
                }
            } else {
                keyboard.hide();
            }
        }
        return touchEvent;
    }

    public View findEditFocus() {
        View currentFocus = slContent != null ? slContent.findFocus() : null;
        return currentFocus instanceof EditText ? currentFocus : null;
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child.getId() == inflate.getId()) {
            super.addView(child, index, params);
        } else {
            if (slContent != null) {
                slContent.addView(child, index, params);
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (inflate != null) {
            ViewGroup.LayoutParams layoutParams1 = inflate.getLayoutParams();
            layoutParams1.width = getMeasuredWidth();
            layoutParams1.height = getMeasuredHeight();
            inflate.setLayoutParams(layoutParams1);
        }
        if (slContent != null && keyboard != null) {
            slContent.setMinimumWidth(getMeasuredHeight() - keyboard.getMeasuredHeight());
        }
    }

    /**
     * 打開關閉軟鍵盤
     */
    public void KeyboardToggle(boolean isShow) {
        if (keyboard != null) {
            if (isShow) {
                keyboard.show();
            } else {
                keyboard.hide();
            }
        }
    }

    /**
     * 打開關閉軟鍵盤
     */
    public void KeyboardToggle(EditText editText) {
        if (keyboard != null && editText != null) {
            keyboard.bindEditText(editText);
            if (editText.hasFocus()) {
                keyboard.show();
            } else {
                keyboard.hide();
            }
        }
    }

    /**
     * @see Constant.KEYBOARD_TYPE
     * @see RandomKeyboard#setKeyboard(int)
     */
    public void setKeyboard(@KeyboardType int type) {
        if (keyboard != null) {
            keyboard.setKeyboard(type);
        }
    }

    /**
     * 隨機打亂key-value
     * @see RandomKeyboard#isRandom(boolean)
     */
    public void isRandom(boolean isRandom) {
        if (keyboard != null) {
            keyboard.isRandom(isRandom);
        }
    }

    public boolean isRandom() {
        return keyboard != null && keyboard.isRandom();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (null != keyboard && keyboard.getVisibility() == VISIBLE) {
                keyboard.hide();
                return true;
            }
        }
        return super.onKeyDown(keyCode, event);
    }
}

其他資源

KeyModel.class

data class KeyModel(var codes: IntArray, var lable: CharSequence)

KEYBOARD_TYPE

public interface Constant {
    interface KEYBOARD_TYPE {
        int TYPE_LETTER = 1;
        int TYPE_NUMBER = 2;
        int TYPE_SYMBOL = 3;
        int TYPE_LETTER_AND_NUM = 4;
        int TYPE_NUM_AND_SYMBOL = 5;
    }
}

@KeyboardType

@IntDef(
    value = [KEYBOARD_TYPE.TYPE_LETTER,
        KEYBOARD_TYPE.TYPE_NUMBER,
        KEYBOARD_TYPE.TYPE_SYMBOL,
        KEYBOARD_TYPE.TYPE_LETTER_AND_NUM,
        KEYBOARD_TYPE.TYPE_NUM_AND_SYMBOL]
)
@Retention(AnnotationRetention.SOURCE)
annotation class KeyboardType

random_keyboard_viewgroup.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/random_keyboard_group"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.core.widget.NestedScrollView
        android:id="@+id/sl_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <com.*.widget.RandomKeyboard
        android:id="@+id/random_keyboard"
        style="@style/RandomKeyboard"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

styles.xml

 <style name="RandomKeyboardParent">
        <item name="android:background">#212121</item>
        <item name="android:keyBackground">@drawable/bg_keyboard</item>
        <item name="android:keyPreviewHeight">50dp</item>
        <item name="android:keyPreviewLayout">@layout/keyboard_preview</item>
        <item name="android:keyPreviewOffset">-20dp</item>
        <item name="android:keyTextColor">#dddddd</item>
        <item name="android:keyTextSize">18sp</item>
        <item name="android:labelTextSize">18sp</item>
        <item name="android:paddingTop">2dp</item>
        <item name="android:paddingBottom">2dp</item>
    </style>

    <style name="RandomKeyboard" parent="RandomKeyboardParent" />

attrs.xml

  <attr name="isRandom" format="boolean" />
    <attr name="keyboardType" format="enum">
        <enum name="TYPE_LETTER" value="1" />
        <enum name="TYPE_NUMBER" value="2" />
        <enum name="TYPE_SYMBOL" value="3" />
        <enum name="TYPE_LETTER_AND_NUM" value="4" />
        <enum name="TYPE_NUM_AND_SYMBOL" value="5" />
    </attr>

    <declare-styleable name="RandomKeyboard">
        <attr name="isRandom"/>
        <attr name="keyboardType"/>
    </declare-styleable>

    <declare-styleable name="RandomKeyboardViewGroup">
        <attr name="isRandom"/>
        <attr name="keyboardType"/>
    </declare-styleable>

keyboard_preview.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_key_preview"
    android:gravity="center"
    android:padding="5dp"
    android:textColor="#4D4D4D"
    android:textSize="20sp"
    android:textStyle="bold"/>

bg_key_preview.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="4dp" />
    <solid android:color="@color/subColorWhite" />
    <stroke
        android:width="1px"
        android:color="@color/gray" />
</shape>

bg_keyboard.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <selector>
            <!-- 按壓後圖層 -->
            <item android:state_pressed="true">
                <shape>
                    <solid android:color="#565656" />
                    <corners android:radius="5dp" />
                </shape>
            </item>
            <!-- 正常狀態圖層 -->
            <item>
                <shape>
                    <solid android:color="#383838" />
                    <corners android:radius="5dp" />
                </shape>
            </item>
        </selector>
    </item>
</layer-list>

letter_keyboard_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyHeight="50dp"
    android:keyWidth="10%p">
    <Row android:rowEdgeFlags="top">
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="q" />
        <Key android:keyLabel="w" />
        <Key android:keyLabel="e" />
        <Key android:keyLabel="r" />
        <Key android:keyLabel="t" />
        <Key android:keyLabel="y" />
        <Key android:keyLabel="u" />
        <Key android:keyLabel="i" />
        <Key android:keyLabel="o" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="p" />
    </Row>
    <Row>
        <Key
            android:horizontalGap="5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="a" />
        <Key android:keyLabel="s" />
        <Key android:keyLabel="d" />
        <Key android:keyLabel="f" />
        <Key android:keyLabel="g" />
        <Key android:keyLabel="h" />
        <Key android:keyLabel="j" />
        <Key android:keyLabel="k" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="l" />
    </Row>
    <Row>
        <Key
            android:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyEdgeFlags="left"
            android:keyLabel="shift"
            android:keyWidth="15%p" />
        <Key android:keyLabel="z" />
        <Key android:keyLabel="x" />
        <Key android:keyLabel="c" />
        <Key android:keyLabel="v" />
        <Key android:keyLabel="b" />
        <Key android:keyLabel="n" />
        <Key android:keyLabel="m" />

        <Key
            android:codes="-5"
            android:isModifier="true"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyLabel="delete"
            android:keyWidth="15%p" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-11"
            android:keyEdgeFlags="left"
            android:keyLabel="123"
            android:keyWidth="15%p" />
        <Key
            android:codes="64"
            android:keyLabel="\@"/>
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyWidth="35%p"
            android:keyLabel="space" />

        <Key android:keyLabel="." />

        <Key
            android:codes="-12"
            android:keyWidth="15%p"
            android:keyLabel="!?#" />
        <Key
            android:codes="-13"
            android:keyWidth="15%p"
            android:keyEdgeFlags="right"
            android:keyLabel="完成" />
    </Row>
</Keyboard>

letter_num_keyboard_layout.xml

<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    android:keyHeight="50dp">

    <Row android:rowEdgeFlags="top">
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="1" />
        <Key android:keyLabel="2" />
        <Key android:keyLabel="3" />
        <Key android:keyLabel="4" />
        <Key android:keyLabel="5" />
        <Key android:keyLabel="6" />
        <Key android:keyLabel="7" />
        <Key android:keyLabel="8" />
        <Key android:keyLabel="9" />
        <Key android:keyEdgeFlags="right"
            android:keyLabel="0" />
    </Row>

    <Row>
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="q" />
        <Key android:keyLabel="w" />
        <Key android:keyLabel="e" />
        <Key android:keyLabel="r" />
        <Key android:keyLabel="t" />
        <Key android:keyLabel="y" />
        <Key android:keyLabel="u" />
        <Key android:keyLabel="i" />
        <Key android:keyLabel="o" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="p" />
    </Row>
    <Row>
        <Key
            android:horizontalGap="5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="a" />
        <Key android:keyLabel="s" />
        <Key android:keyLabel="d" />
        <Key android:keyLabel="f" />
        <Key android:keyLabel="g" />
        <Key android:keyLabel="h" />
        <Key android:keyLabel="j" />
        <Key android:keyLabel="k" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="l" />
    </Row>
    <Row>
        <Key
            android:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyWidth="15%p"
            android:keyHeight="100dp"
            android:keyEdgeFlags="left"
            android:keyLabel="shift" />
        <Key android:keyLabel="z" />
        <Key android:keyLabel="x" />
        <Key android:keyLabel="c" />
        <Key android:keyLabel="v" />
        <Key android:keyLabel="b" />
        <Key android:keyLabel="n" />
        <Key android:keyLabel="m" />

        <Key
            android:codes="-5"
            android:isModifier="true"
            android:isRepeatable="true"
            android:keyWidth="15%p"
            android:keyEdgeFlags="right"
            android:keyLabel="delete" />
    </Row>

    <Row android:rowEdgeFlags="bottom">

        <Key
            android:codes="64"
            android:horizontalGap="15%p"
            android:keyWidth="15%p"
            android:keyLabel="\@"/>

        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyWidth="40%p"
            android:keyLabel="space" />

        <Key
            android:codes="-12"
            android:keyWidth="15%p"
            android:keyLabel="!?#" />

        <Key
            android:codes="-13"
            android:isRepeatable="true"
            android:keyWidth="15%p"
            android:keyEdgeFlags="right"
            android:keyLabel="完成" />
    </Row>
</Keyboard>

num_symbol_keyboard_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0.9%p"
    android:keyWidth="9%p"
    android:keyHeight="52dp"
    android:verticalGap="0px">

    <Row>
        <Key
            android:codes="49"
            android:keyLabel="1" />
        <Key
            android:codes="50"
            android:keyLabel="2" />
        <Key
            android:codes="51"
            android:keyLabel="3" />
        <Key
            android:codes="52"
            android:keyLabel="4" />
        <Key
            android:codes="53"
            android:keyLabel="5" />
        <Key
            android:codes="54"
            android:keyLabel="6" />

        <Key
            android:codes="55"
            android:keyLabel="7" />
        <Key
            android:codes="56"
            android:keyLabel="8" />


        <Key
            android:codes="57"
            android:keyLabel="9" />
        <Key
            android:codes="48"
            android:keyLabel="0" />
    </Row>

    <Row>
        <Key
            android:codes="45"
            android:keyLabel="-" />
        <Key
            android:codes="47"
            android:keyLabel="/" />
        <Key
            android:codes="58"
            android:keyLabel=":" />
        <Key
            android:codes="59"
            android:keyLabel=";" />
        <Key
            android:codes="40"
            android:keyLabel="(" />
        <Key
            android:codes="41"
            android:keyLabel=")" />
        <Key
            android:codes="36"
            android:keyLabel="$" />
        <!--&-->
        <Key
            android:codes="38"
            android:keyLabel="&#038;" />
        <Key
            android:codes="64"
            android:keyLabel="\@" />
        <Key
            android:codes="34"
            android:keyLabel="&#034;" />
    </Row>

    <Row>
        <Key
            android:codes="-12"
            android:keyWidth="11.5%p"
            android:keyEdgeFlags="left"
            android:keyLabel="!?#" />
        <Key
            android:codes="46"
            android:keyLabel="." />
        <Key
            android:codes="44"
            android:keyLabel="," />
        <Key
            android:codes="63"
            android:keyLabel="\?" />
        <Key
            android:codes="33"
            android:keyLabel="!" />
        <Key
            android:codes="39"
            android:keyLabel="'" />
        <Key
            android:codes="42"
            android:keyLabel="*" />
        <Key
            android:codes="43"
            android:keyLabel="+" />
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyWidth="16.5%p"
            android:keyEdgeFlags="right"
            android:keyLabel="delete" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-10"
            android:keyWidth="22%p"
            android:keyLabel="ABC" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyWidth="50.4%p"
            android:keyLabel="space" />
        <Key
            android:codes="-13"
            android:keyWidth="24%p"
            android:keyEdgeFlags="right"
            android:keyLabel="完成" />
    </Row>
</Keyboard>

number_keyboard_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="25%p"
    android:keyHeight="50dp">
    <Row>
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="1" />
        <Key android:keyLabel="2" />
        <Key android:keyLabel="3" />
        <Key
            android:codes="-5"
            android:isModifier="true"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyLabel="delete" />
    </Row>
    <Row>
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="4" />
        <Key android:keyLabel="5" />
        <Key android:keyLabel="6" />
        <Key
            android:codes="-12"
            android:keyEdgeFlags="right"
            android:keyLabel="!?#" />
    </Row>
    <Row>
        <Key
            android:keyEdgeFlags="left"
            android:keyLabel="7" />
        <Key android:keyLabel="8" />
        <Key android:keyLabel="9" />
        <Key
            android:keyEdgeFlags="right"
            android:keyLabel="." />
    </Row>
    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-10"
            android:keyWidth="25%p"
            android:keyEdgeFlags="left"
            android:keyLabel="ABC" />
        <Key
            android:codes="48"
            android:keyWidth="50%p"
            android:keyLabel="0" />
        <Key
            android:codes="-13"
            android:keyWidth="25%p"
            android:keyEdgeFlags="right"
            android:keyLabel="完成" />
    </Row>
</Keyboard>

symbol_keyboard_layout.xml

<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyHeight="52dp"
    android:keyWidth="9%p"
    android:horizontalGap="0.9%p"
    android:verticalGap="0px">
    <Row>
        <Key
            android:codes="91"
            android:keyEdgeFlags="left"
            android:keyLabel="["/>
        <Key
            android:codes="93"
            android:keyLabel="]"/>
        <Key
            android:codes="123"
            android:keyLabel="{"/>
        <Key
            android:codes="125"
            android:keyLabel="}"/>
        <Key
            android:codes="35"
            android:keyLabel="#"/>
        <Key
            android:codes="37"
            android:keyLabel="%"/>
        <Key
            android:codes="94"
            android:keyLabel="^"/>
        <Key
            android:codes="42"
            android:keyLabel="*"/>
        <Key
            android:codes="43"
            android:keyLabel="+"/>
        <Key
            android:codes="61"
            android:keyEdgeFlags="right"
            android:keyLabel="="/>
    </Row>
    <Row>
        <Key
            android:codes="95"
            android:keyEdgeFlags="left"
            android:keyLabel="_"/>
        <Key
            android:codes="92"
            android:keyLabel="\&#092;"/>
        <Key
            android:codes="124"
            android:keyLabel="|"/>
        <Key
            android:codes="126"
            android:keyLabel="~"/>

        <!--<-->
        <Key
            android:codes="60"
            android:keyLabel="&#060;"/>
        <!-->-->
        <Key
            android:codes="62"
            android:keyLabel="&#062;"/>
        <Key
            android:codes="8364"
            android:keyLabel="€"/>
        <Key
            android:codes="163"
            android:keyLabel="£"/>
        <Key
            android:codes="165"
            android:keyLabel="¥"/>

        <!-- todo • -->
        <Key
            android:codes="8226"
            android:keyLabel="•"/>
    </Row>

    <Row>
        <Key
            android:codes="-11"
            android:keyEdgeFlags="left"
            android:keyLabel="123"
            android:keyWidth="16.9%p" />
        <Key
            android:codes="45"
            android:keyLabel="-" />
        <Key
            android:codes="46"
            android:keyLabel="." />
        <Key
            android:codes="44"
            android:keyLabel="," />
        <Key
            android:codes="63"
            android:keyLabel="\?" />
        <Key
            android:codes="33"
            android:keyLabel="!" />
        <Key
            android:codes="39"
            android:keyLabel="'" />
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyWidth="21%p"
            android:keyEdgeFlags="right"
            android:keyLabel="delete" />
    </Row>

    <Row android:rowEdgeFlags="bottom">
        <Key
            android:codes="-10"
            android:keyWidth="22%p"
            android:keyLabel="ABC" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyWidth="50.4%p"
            android:keyLabel="space" />
        <Key
            android:codes="-13"
            android:keyWidth="24%p"
            android:keyEdgeFlags="right"
            android:keyLabel="完成" />
    </Row>

</Keyboard>

附(KeyboardView,keyboard,Key,Row屬性解釋)

  • Keyboard
參數 值類型 釋義 傳值
keyHeight dimension/fractional key高度 精確值(dp、px等)和相對值(%、%p)
keyWidth dimension/fractional key寬度 同上
horizontalGap dimension/fractional key間水平間隙 同上
verticalGap dimension/fractional key間垂直間隙 同上
  • Row
參數 值類型 釋義 傳值
keyHeight dimension/fractional key高度 精確值(dp、px等)和相對值(%、%p)
keyWidth dimension/fractional key寬度 同上
horizontalGap dimension/fractional key間水平間隙 同上
verticalGap dimension/fractional key間垂直間隙 同上
keyboardMode reference 鍵盤模式,不符該模式則跳過此行
rowEdgeFlags enum 行邊界標記 top/bottom,鍵盤頂部和底部
  • Key
參數 值類型 釋義 傳值
keyHeight dimension/fractional key高度 精確值(dp、px等)和相對值(%、%p)
keyWidth dimension/fractional key寬度 同上
horizontalGap dimension/fractional key間水平間隙 同上
verticalGap dimension/fractional key間垂直間隙 同上
keyEdgeFlags enum Key邊緣位置標記 left/right,鍵盤左邊和右邊
codes int Key輸出符號對應的Unicode值
iconPreview reference 彈出回顯的控件 佈局資源
isModifier boolean 是否爲功能鍵,如:Alt/Shift
isRepeatable boolean 是否允許長按重複執行
isSticky boolean 是否是開關鍵,例如Shift大小寫切換按鍵,具有兩種狀態,按下狀態和正常狀態,取值爲true或則false。
keyIcon reference 替換label顯示在按鍵上的圖標 圖片資源
keyLabel reference 顯示在Key上的標籤 字符
keyOutputText string Key按下時輸出的字符或字符串
popupCharacters string 小鍵盤顯示的字符,用於顯示Key候選項。
popupKeyboard reference 按鍵候選小鍵盤的keyboard佈局 佈局資源
  • KeyboardView
參數 值類型 釋義 傳值
keyBackground reference 按鍵的圖像背景,必須包含多個狀態的drawable
verticalCorrection dimension 補充觸摸y座標的偏移,用於偏差矯正
keyPreviewLayout reference 按鍵按下時預覽框的佈局
keyPreviewOffset dimension 按鍵按下時預覽框的偏移。>0 向下,<0 向上。
keyPreviewHeight dimension 按鍵按下時預覽框的高度。
keyTextSize dimension 按鍵文字大小。
keyTextColor color 按鍵文字顏色。
labelTextSize dimension 標籤文字大小,keylabel有多個字符且keycodes只有一個值時,該屬性生效。
popupLayout reference 按鍵候選小鍵盤的KeyboardView佈局。
shadowRadius float 按鍵文字陰影半徑
shadowColor color 按鍵文字陰影顏色
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章