android实现仿真键盘(KeyboardView适配)

原生的键盘布局声明了@deprecated被废弃,虽然可以使用但明显不合需求。

/**
 * @deprecated This class is deprecated because this is just a convenient UI widget class that
 *             application developers can re-implement on top of existing public APIs.  If you have
 *             already depended on this class, consider copying the implementation from AOSP into
 *             your project or re-implementing a similar widget by yourselves
 */
@Deprecated
public class KeyboardView extends View implements View.OnClickListener {

因此对KeyboardView的代码进行迁移和修改适配,形成自己项目特有的自定义View。

具体修改适配如下:

增加左上角增加小标签/小图标显示:
在这里插入图片描述

        /** Small label to display */
        public CharSequence smallLabel;
        /** Small Icon to display instead of a small label. Small icon takes precedence over a small label */
        public Drawable smallIcon;

BKeyboard.java中增加适配上和下按键,竖直摆放。verticalFlags属性分为topbottom,代表位于同一列。
∂

      /**
         * Flags that specify the anchoring to vertical of the key
         * that are just out of the boundary of the key. This is a bit mask of
         * {@link BKeyboard#VERTICAL_TOP} and {@link BKeyboard#VERTICAL_BOTTOM}.
         */
        public int verticalFlags;

loadKeyboard方法对verticalFlags属性的按键特殊处理,verticalFlags属性为topbottom代表按键在同一列,计算为一个宽度,x坐标不变,y坐标偏移。

} else if (event == XmlResourceParser.END_TAG) {
    if (inKey) {
        inKey = false;
        if (key.verticalFlags == VERTICAL_TOP) {
            y += key.height + key.gap / 2;
        } else {
            x += key.gap + key.width;
            y = row * (currentRow.verticalGap + currentRow.defaultHeight);
            if (x > mTotalWidth) {
                mTotalWidth = x;
            }
        }
    } else if (inRow) {
        inRow = false;
        y += currentRow.verticalGap;
        y += currentRow.defaultHeight;
        row++;
    } else {
        // TODO: error or extend?
    }
 }

调整verticalFlags属性按键的坐标轴位置,同一列x不变。

final void resize(int newWidth, int newHeight) {
        int numRows = rows.size();
        for (int rowIndex = 0; rowIndex < numRows; ++rowIndex) {
            Row row = rows.get(rowIndex);
            int numKeys = row.mKeys.size();
            int totalGap = 0;
            int totalWidth = 0;
            for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
                Key key = row.mKeys.get(keyIndex);
                if (keyIndex > 0) {
                    //By Evin, key align top or bottom of the bound as one key
                    if (key.verticalFlags != VERTICAL_TOP) {
                        totalGap += key.gap;
                    }
                }
                //By Evin, key align top or bottom of the bound as one key
                if (key.verticalFlags != VERTICAL_TOP) {
                    totalWidth += key.width;
                }
            }
            if (totalGap + totalWidth > newWidth) {
                int x = 0;
                float scaleFactor = (float)(newWidth - totalGap) / totalWidth;
                for (int keyIndex = 0; keyIndex < numKeys; ++keyIndex) {
                    Key key = row.mKeys.get(keyIndex);
                    key.width *= scaleFactor;
                    //By Evin,verticalFlags for vertical key
                    key.x = x;
                    if (key.verticalFlags != VERTICAL_TOP) {
                        x += key.width + key.gap;
                    }
                }
            }
        }
        mTotalWidth = newWidth;
    }

BKeyboardView.detectAndSendKey方法增加快速点击的监听:

// Multi-tap
if (mInMultiTap) {
    if (mTapCount != -1) {
        mKeyboardActionListener.onKey(BKeyboard.KEYCODE_MULTI_TAP, new int[] {code});
    } else {
        mTapCount = 0;
    }
    code = key.codes[mTapCount];
}

增加适配可以变换如Caps Lock的按键:
在这里插入图片描述

    <!-- Whether this is a shifted key, such as Caps lock. -->
        <attr name="isShifted" format="boolean" />

同时增加多点触控的适配使其能多个按键同时按下:

        ...
 final int action = me.getActionMasked();
        touchX = (int) me.getX(me.getActionIndex()) - getPaddingLeft();
        touchY = (int) me.getY(me.getActionIndex()) - getPaddingTop();
         ...
         case MotionEvent.ACTION_POINTER_DOWN:
         ...
         case MotionEvent.ACTION_POINTER_UP:
         ...

按键表keyboard_normal.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:app="http://schemas.android.com/apk/res-auto"
    app:horizontalGap="0.8%p"
    app:keyWidth="10%p"
    app:keyHeight="46dp"
    app:verticalGap="2%p">
    <Row>
        <Key
            app:codes="41"
            app:keyWidth="8%p"
            app:keyEdgeFlags="left"
            app:keyLabel="esc" />
        <Key
            app:codes="30"
            app:keyWidth="6%p"
            app:keyLabel="f1" />
        <Key
            app:codes="31"
            app:keyWidth="6%p"
            app:keyLabel="f2" />
        <Key
            app:codes="32"
            app:keyWidth="6%p"
            app:keyLabel="f3" />
        <Key
            app:codes="33"
            app:keyWidth="6%p"
            app:keyLabel="f4" />
        <Key
            app:codes="34"
            app:keyWidth="6%p"
            app:keyLabel="f5" />
        <Key
            app:codes="35"
            app:keyWidth="6%p"
            app:keyLabel="f6" />
        <Key
            app:codes="36"
            app:keyWidth="6%p"
            app:keyLabel="f7" />
        <Key
            app:codes="37"
            app:keyWidth="6%p"
            app:keyLabel="f8" />
        <Key
            app:codes="38"
            app:keyWidth="6%p"
            app:keyLabel="f9" />
        <Key
            app:codes="39"
            app:keyWidth="6%p"
            app:keyLabel="f10" />
        <Key
            app:codes="45"
            app:keyWidth="6%p"
            app:keyLabel="f11" />
        <Key
            app:codes="46"
            app:keyWidth="6%p"
            app:keyLabel="f12" />
        <Key
            app:codes="76"
            app:keyWidth="8%p"
            app:keyEdgeFlags="right"
            app:isRepeatable="true"
            app:keyLabel="del" />
    </Row>
    <Row>
        <Key
            app:codes="50"
            app:keyWidth="6%p"
            app:keyEdgeFlags="left"
            app:keySmallLabel="~"
            app:keyLabel="`" />
        <Key
            app:codes="30"
            app:keyWidth="6%p"
            app:keySmallLabel="!"
            app:keyLabel="1" />
        <Key
            app:codes="31"
            app:keyWidth="6%p"
            app:keySmallLabel="\@"
            app:keyLabel="2" />
        <Key
            app:codes="32"
            app:keyWidth="6%p"
            app:keySmallLabel="#"
            app:keyLabel="3" />
        <Key
            app:codes="33"
            app:keyWidth="6%p"
            app:keySmallLabel="¥"
            app:keyLabel="4" />
        <Key
            app:codes="34"
            app:keyWidth="6%p"
            app:keySmallLabel="%"
            app:keyLabel="5" />
        <Key
            app:codes="35"
            app:keyWidth="6%p"
            app:keySmallLabel="^"
            app:keyLabel="6" />
        <Key
            app:codes="36"
            app:keyWidth="6%p"
            app:keySmallLabel="&amp;"
            app:keyLabel="7" />
        <Key
            app:codes="37"
            app:keyWidth="6%p"
            app:keySmallLabel="*"
            app:keyLabel="8" />
        <Key
            app:codes="38"
            app:keyWidth="6%p"
            app:keySmallLabel="("
            app:keyLabel="9" />
        <Key
            app:codes="39"
            app:keyWidth="6%p"
            app:keySmallLabel=")"
            app:keyLabel="0" />
        <Key
            app:codes="45"
            app:keyWidth="6%p"
            app:keySmallLabel="—"
            app:keyLabel="-" />
        <Key
            app:codes="46"
            app:keyWidth="6%p"
            app:keySmallLabel="+"
            app:keyLabel="=" />
        <Key
            app:codes="42"
            app:keyWidth="10%p"
            app:keyEdgeFlags="right"
            app:isRepeatable="true"
            app:keyLabel="back" />
    </Row>
    <Row>
        <Key
            app:codes="43"
            app:keyWidth="10%p"
            app:keyEdgeFlags="left"
            app:keyLabel="tab" />
        <Key
            app:codes="20"
            app:keyWidth="6%p"
            app:keyLabel="Q" />
        <Key
            app:codes="26"
            app:keyWidth="6%p"
            app:keyLabel="W" />
        <Key
            app:codes="8"
            app:keyWidth="6%p"
            app:keyLabel="E" />
        <Key
            app:codes="21"
            app:keyWidth="6%p"
            app:keyLabel="R" />
        <Key
            app:codes="23"
            app:keyWidth="6%p"
            app:keyLabel="T" />
        <Key
            app:codes="28"
            app:keyWidth="6%p"
            app:keyLabel="Y" />
        <Key
            app:codes="24"
            app:keyWidth="6%p"
            app:keyLabel="U" />
        <Key
            app:codes="12"
            app:keyWidth="6%p"
            app:keyLabel="I" />
        <Key
            app:codes="18"
            app:keyWidth="6%p"
            app:keyLabel="O" />
        <Key
            app:codes="19"
            app:keyWidth="6%p"
            app:keyLabel="P" />
        <Key
            app:codes="47"
            app:keyWidth="6%p"
            app:keySmallLabel="{"
            app:keyLabel="[" />
        <Key
            app:codes="48"
            app:keyWidth="6%p"
            app:keySmallLabel="}"
            app:keyLabel="]" />
        <Key
            app:codes="49"
            app:keyWidth="6%p"
            app:keyEdgeFlags="right"
            app:keySmallLabel="|"
            app:keyLabel="\\" />

    </Row>

    <Row>
        <Key
            app:codes="57"
            app:keyWidth="11.4%p"
            app:keyEdgeFlags="left"
            app:isShifted="true"
            app:keyLabel="caps" />
        <Key
            app:codes="4"
            app:keyWidth="6%p"
            app:keyLabel="A" />
        <Key
            app:codes="22"
            app:keyWidth="6%p"
            app:keyLabel="S" />
        <Key
            app:codes="7"
            app:keyWidth="6%p"
            app:keyLabel="D" />
        <Key
            app:codes="9"
            app:keyWidth="6%p"
            app:keyLabel="F" />
        <Key
            app:codes="10"
            app:keyWidth="6%p"
            app:keyLabel="G" />
        <Key
            app:codes="11"
            app:keyWidth="6%p"
            app:keyLabel="H" />
        <Key
            app:codes="13"
            app:keyWidth="6%p"
            app:keyLabel="J" />
        <Key
            app:codes="14"
            app:keyWidth="6%p"
            app:keyLabel="K" />
        <Key
            app:codes="15"
            app:keyWidth="6%p"
            app:keyLabel="L" />
        <Key
            app:codes="51"
            app:keyWidth="6%p"
            app:keySmallLabel=':'
            app:keyLabel=";" />
        <Key
            app:codes="52"
            app:keyWidth="6%p"
            app:keySmallLabel='"'
            app:keyLabel="'" />
        <Key
            app:codes="40"
            app:keyWidth="11.4%p"
            app:keyLabel="enter"
            app:keyEdgeFlags="right"/>

    </Row>

    <Row>
        <Key
            app:codes="-1001"
            app:keyWidth="14.8%p"
            app:keyEdgeFlags="left"
            app:isModifier="true"
            app:keyLabel="shift" />
        <Key
            app:codes="29"
            app:keyWidth="6%p"
            app:keyLabel="Z" />
        <Key
            app:codes="27"
            app:keyWidth="6%p"
            app:keyLabel="X" />
        <Key
            app:codes="6"
            app:keyWidth="6%p"
            app:keyLabel="C" />
        <Key
            app:codes="25"
            app:keyWidth="6%p"
            app:keyLabel="V" />
        <Key
            app:codes="5"
            app:keyWidth="6%p"
            app:keyLabel="B" />
        <Key
            app:codes="17"
            app:keyWidth="6%p"
            app:keyLabel="N" />
        <Key
            app:codes="16"
            app:keyWidth="6%p"
            app:keyLabel="M" />
        <Key
            app:codes="16"
            app:keyWidth="6%p"
            app:keySmallLabel="&lt;"
            app:keyLabel="," />
        <Key
            app:codes="16"
            app:keyWidth="6%p"
            app:keySmallLabel="&gt;"
            app:keyLabel="." />
        <Key
            app:codes="16"
            app:keyWidth="6%p"
            app:keySmallLabel='?'
            app:keyLabel="/" />
        <Key
            app:codes="-1"
            app:keyLabel="shift"
            app:keyEdgeFlags="right"
            app:keyWidth="14.8%p" />
    </Row>
    <Row>
        <Key
            app:codes="-1004"
            app:keyWidth="6%p"
            app:keyEdgeFlags="left"
            app:isModifier="true"
            app:keyLabel="ctrl" />
        <Key
            app:codes="-1006"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="fn" />
        <Key
            app:codes="-1005"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyIcon="@drawable/ic_win" />
        <Key
            app:codes="-1006"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="alt" />
        <Key
            app:codes="44"
            app:keyWidth="37.2%p"
            app:keyLabel="space"
            app:isRepeatable="true"/>
        <Key
            app:codes="-1006"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="alt" />
        <Key
            app:codes="-1006"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="ctrl" />

        <Key
            app:codes="80"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="◀︎" />
        <Key
            app:codes="82"
            app:keyVerticalFlags="top"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyLabel="▲" />
        <Key
            app:codes="81"
            app:keyWidth="6%p"
            app:keyVerticalFlags="bottom"
            app:isModifier="true"
            app:keyLabel="▼" />
        <Key
            app:codes="79"
            app:keyWidth="6%p"
            app:isModifier="true"
            app:keyEdgeFlags="right"
            app:keyLabel="▶︎︎" />
    </Row>
</Keyboard>

用法和KeyboardView类似,只不过需要声明 xmlns:app="http://schemas.android.com/apk/res-auto"的app属性作用域,以免与系统的android属性冲突。
当然还有一些细节修改,此处不贴代码了。

使用方式如下:

        BKeyboardView keyboardView = findViewById(R.id.keyboard_view);
        keyboardView.setPreviewEnabled(false); // 取消按键弹框的显示
        keyboardView.setOnKeyboardActionListener(new BKeyboardView.OnKeyboardActionListener() {
            @Override
            public void onPress(int primaryCode) {
                
            }

            @Override
            public void onRelease(int primaryCode) {
                
            }

            @Override
            public void onKey(int primaryCode, int[] keyCodes) {
                sendKey(primaryCode);
                playClick(primaryCode);
            }

            @Override
            public void onText(CharSequence text) {

            }

            @Override
            public void swipeLeft() {

            }

            @Override
            public void swipeRight() {

            }

            @Override
            public void swipeDown() {

            }

            @Override
            public void swipeUp() {

            }
        });

可以自定义播放不同的按键声音:

    private void playClick(int keyCode){
        //Todo play different click audio for different keycode
        mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);
        // mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);
        // mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);
        // mAudioManager.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);
    }

仿真键盘效果如下:
在这里插入图片描述

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言并肃

感谢大哥支持!您的鼓励是我动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值