Android:最快实现一个自定义键盘

现在很多场景需要使用自定义键盘,比如银行app的乱序密码键盘。现在做个demo,用最快的速度、最少的代码做出一个数字键盘,有基本的操作按键,效果如下图:

自定义键盘

自定义键盘的实现,需要用到系统KeyboardKeybaordView两个类。

Keyboard

Keybard类可以加载一个描述键盘按键的xml文件,demo里的按键布局如下:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="1dp"
    android:verticalGap="1dp"
    android:keyWidth="20%p"
    android:keyHeight="50dp">
    <Row>
        <Key android:codes="-10" android:keyLabel="清空"
            android:keyEdgeFlags="left"/>
        <Key android:codes="49" android:keyLabel="1"/>
        <Key android:codes="50" android:keyLabel="2"/>
        <Key android:codes="51" android:keyLabel="3"/>
        <Key android:codes="-3" android:keyLabel="收起"
            android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="-11" android:keyLabel="上一项"
            android:keyEdgeFlags="left"
            android:keyHeight="100.5dp"/>
        <Key android:codes="52" android:keyLabel="4"/>
        <Key android:codes="53" android:keyLabel="5"/>
        <Key android:codes="54" android:keyLabel="6"/>
        <Key android:codes="-12" android:keyLabel="下一项"
            android:keyEdgeFlags="right"
            android:keyHeight="100.5dp"/>
    </Row>
    <Row>
        <Key android:codes="-99" android:keyHeight="0dp" android:keyEdgeFlags="left"/>
        <Key android:codes="55" android:keyLabel="7"/>
        <Key android:codes="56" android:keyLabel="8"/>
        <Key android:codes="57" android:keyLabel="9"/>
        <Key android:codes="-99" android:keyHeight="0dp" android:keyEdgeFlags="right"/>
    </Row>
    <Row>
        <Key android:codes="-99" android:keyEdgeFlags="left"/>
        <Key android:codes="45" android:keyLabel="-"/>
        <Key android:codes="48" android:keyLabel="0"/>
        <Key android:codes="46" android:keyLabel="."/>
        <Key android:codes="-5" android:keyLabel="删除"
            android:keyEdgeFlags="right"
            android:isRepeatable="true"/>
    </Row>
</Keyboard>

要注意的地方是:

  • 键盘布局放在/res/xml
  • 输出字符按键的android:codes需要是对应的ASCII码
  • 有预定义常用操作,比如取消、完成、删除,可以直接用

比较折腾的是不知道如何让按键跨行跨列,文档里没有找到任何span方法。跨列容易解决,单独修改keyWidth就可以。跨行的话,现在的实现是让上一行key的height双倍,下一行的height为0,最终实现demo的效果,求更好的方法。

KeyboardView

KeyboardView处理了键盘的绘制、触摸、滑动等动作,加进Activity的布局里。

<android.inputmethodservice.KeyboardView
            android:id="@+id/custom_keyboard"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:background="@color/lightgray"
            android:keyBackground="@drawable/btn_keyboard_key"
            android:keyTextColor="@color/black"
            android:keyTextSize="20dp"
            android:paddingTop="1px"
            android:shadowRadius="0"
            android:visibility="gone"/>

具体属性参考官方文档,到这里,自定义键盘的ui已经定义好,下面看怎样跑起来。

键盘初始化

private void initKeyboard() {
        Keyboard keyboard = new Keyboard(this, R.xml.number_input_keyboard);

        mBinding.customKeyboard.setKeyboard(keyboard);
        mBinding.customKeyboard.setEnabled(true);
        mBinding.customKeyboard.setPreviewEnabled(false);
        mBinding.customKeyboard.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {
            @Override
            public void onPress(int primaryCode) {
            }

            @Override
            public void onRelease(int primaryCode) {
            }

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

            @Override
            public void onText(CharSequence text) {
            }

            @Override
            public void swipeLeft() {
            }

            @Override
            public void swipeRight() {
            }

            @Override
            public void swipeDown() {
            }

            @Override
            public void swipeUp() {
            }
        });
    }

Keyboard和KeyboardView的初始化很简单,最重要的是实现OnKeyboardActionListener,提供了多个动作的回调,demo简单实现按键点击的处理。

    private void doCustomKeyboardKey(int primaryCode, int[] keyCodes) {
        Editable editable;
        int selectionStart;
        if (mBinding.et1.isFocused()) {
            editable = mBinding.et1.getText();
            selectionStart = mBinding.et1.getSelectionStart();
        } else {
            editable = mBinding.et2.getText();
            selectionStart = mBinding.et2.getSelectionStart();
        }

        if (primaryCode == Keyboard.KEYCODE_CANCEL) {
            hideKeyboard();
        } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
            if (editable.length() > 0 && selectionStart > 0) {
                editable.delete(selectionStart - 1, selectionStart);
            }
        } else if (primaryCode == -10) {
            if (editable.length() > 0) {
                editable.clear();
            }
        } else if (primaryCode == -11) {
            mBinding.et1.requestFocus();
        } else if (primaryCode == -12) {
            mBinding.et2.requestFocus();
        } else if (primaryCode == -99) {
            //do nothing
        } else {
            editable.insert(selectionStart, Character.toString((char) primaryCode));
        }
    }

根据xml文件里预定好的primaryCode,根据实际情况处理各个按键的效果。

自定义EditText

使用自定义键盘的EditText需要增加处理系统键盘,最简单的方法就是直接隐藏。

@Override
public boolean onTouchEvent(MotionEvent event) {
    super.onTouchEvent(event);
    requestFocus();
    requestFocusFromTouch();

    hideSysInput();

    return true;
}

自定义键盘的打开

mBinding.et1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mBinding.customKeyboard.setVisibility(View.VISIBLE);
    }
});

EditText增加监听onClick事件,直接让键盘显示。为什么不用OnFocusChangeListener呢,因为主动收起键盘,EditText的焦点没有改变,只有onClick才能再触发键盘打开。

几段代码就实现了一个自定义键盘,挺简单的。在此基础上,根据实际业务,我们可以扩展做出更复杂的效果。最后附上demo地址,谢谢观看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,051评论 25 707
  • 最近项目中在做一个股票交易需求升级, 产品对于输入方式有一些特殊的要求, 具体就是对于输入键盘加了诸多限制. 这就...
    kangqiao182阅读 15,225评论 1 23
  • 在接入环信SDK之后,得知服务器端加这个敏感词库是增值服务,并且价格还不菲,在百度谷歌之后,实现了从iOS 端处理...
    Vinvinda阅读 3,460评论 0 1
  • 以前从未接触过生涯规划、职场充电、鸡汤励志软文等等,自从进了读书会,读到各种公众号的推送的文章,还有简书里各个大咖...
    小萤子阅读 510评论 10 3
  • mysqli 操作数据库 从PHP5.0开始可以使用MySQLi,是一种面向对象的技术(以后新加功能都会以对象形式...
    Ayong丶阅读 721评论 0 0