一、实现原理

实现软键盘主要用到了系统的两个类 Keyboard 和 KeyboardView .

1. Keyboard

用于监听虚拟键盘:

  • Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard consists of rows of keys . The layout file for a keyboard contains XML that looks like the following snippet :
"%10p"         android:keyHeight="50px"         android:horizontalGap="2px"         android:verticalGap="2px" >     "32px" >         "A" />         ...          ... 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

我们自定义的每一个按键都将会有一个 codes 值,比如回退我们就写成:

<Key android:codes="-5"      android:keyIcon="@drawable/sym_keyboard_delete"/>
  • 1
  • 2
  • 1
  • 2

再监听就是:

if (primaryCode == Keyboard.KEYCODE_DELETE){}
  • 1
  • 1

这就表示,监听 delete 事件了! 
定义  标签时常用到的 codes / KEYCODE 有:

    public static final int KEYCODE_SHIFT = -1;    public static final int KEYCODE_MODE_CHANGE = -2;    public static final int KEYCODE_CANCEL = -3;    public static final int KEYCODE_DONE = -4;    public static final int KEYCODE_DELETE = -5;    public static final int KEYCODE_ALT = -6;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2. KeyboardView

处理绘制,检测按键,触摸动作:

  • A view that renders a virtual Keyboard. It handles rendering of keys and detecting key presses and touch movements.

我们会在Activity的xml文件中这样定义:

"@+id/keyboard_view"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_alignParentBottom="true"            android:background="@color/gray"            android:focusable="true"            android:focusableInTouchMode="true"            android:keyBackground="@drawable/bg_keyboard_selector"            android:keyTextColor="@color/keyTextColor"            android:visibility="gone"            android:keyPreviewLayout="@layout/key_preview_layout"            />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 其中 android:keyPreviewLayout 指的是每当我们点击键盘上的某个键时,短暂弹出的布局。
属性名 描述
android:keyBackground Image for the key.
android:keyPreviewLayout Layout resource for key press feedback.
android:keyPreviewOffset Vertical offset of the key press feedback from the key.
android:keyTextColor Color to use for the label in a key.
android:keyTextSize Size of the text for character keys.
android:labelTextSize Size of the text for custom keys with some text and no icon.
android:popupLayout Layout resource for popup keyboards.
android:verticalCorrection Amount to offset the touch Y coordinate by, for bias correction.
  • 我们需要建一个xml文件,来布局我们的视图, 
    一般是在res文件夹中建一个名为xml的文件夹,在里面新建立一个xml布局文件。

  • 每一个按键的属性主要包括 
    Android:codes=" " 和 android:keyLabel="" 
    Activity 就是根据 codes 的值来监听的。 
    一些可以自定义设置,一些需要是 keyboard 中设置好的,要保持一致。

二、实例解析:在xml文件中定义

1. 效果图:

Android 总结:自定义键盘实现原理和三种实例详解_第1张图片 
建一个类,用于处理软键盘事件,文件名为 KeyboardUtil.Java

2. 定义键盘的键

键盘上键的细节和它的位置我们指定在一个xml文件中,每一个键都有如下的属性,

  • keyLabel 这个属性是指每个键显示的文本
  • codes 这个属性是指这个键代表的字符的unicode

例如,我们定义了一个字母A, 
codes 属性的值是97keyLabel属性的值就是A

如果一个code对应多个key,这个key代表的字符取决于这个key接受到的点击数taps,例如,一个键具有63,33,58编码:

  • 一次点击就是 ?
  • 两次点击就是 !
  • 三次点击就是 :

一个 key 还可以有一些可选的属性:

  • keyEdgeFlags 这个属性的值可以是left或者right 
    这个属性通常加在一行中最左边和最右边的键上。
  • keyWidth 这个属性定义了键的宽度,通常是一个百分比的值。
  • isRepeatable 这个属性如果设置为true,那么当长按该键时就会 
    重复接受到该键上的动作,在 删除键键 和 空格键 上通常设为true

键盘上的键都是按行分组,通常情况下我们每行上的键限制到10个以内 
英文键盘建议每个键占整个键盘宽度的10%,我们将键的高度设置为60dp,这个值可以调整,但是不建议设置低于48dp .

有些键的code是负数,负数等于在Keyboard类 
中预定义的常量,例如,-5等于Keyboard.KEYCODE_DELETE

3. 定义按键声音

创建一个方法,这个方法的作用就是当我们按下某个键时发出一个声音,我们使用 AudioManager 来播放这个声音,Android SDK给我们提供了一些键盘的声效,我们在自己定义的playClick()方法中使用。

private void playClick(int keyCode){    AudioManager am = (AudioManager)getSystemService(AUDIO_SERVICE);    switch(keyCode){    case 32:        am.playSoundEffect(AudioManager.FX_KEYPRESS_SPACEBAR);        break;    case Keyboard.KEYCODE_DONE:    case 10:        am.playSoundEffect(AudioManager.FX_KEYPRESS_RETURN);        break;    case Keyboard.KEYCODE_DELETE:        am.playSoundEffect(AudioManager.FX_KEYPRESS_DELETE);        break;    default:        am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

4. 处理按键输入

当用户按下键盘上的一个键时,onKey()方法 会被调用,并且发送这个 键的unicode值,基于这个值,键盘可以执行以下动作:

  • 如果code是 KEYCODE_DELETE,使用deleteSurroundingText()方法删除光标左边的字符。
  • 如果code是 KEYCODE_DONE , KEYCODE_ENTER 事件会被发送。
  • 如果code是 KEYCODE_SHIFT,boolean类型的caps的值会被改变,并且使用 setShifted() 方法改变键盘的换档状态(shift state),当状态改变时,键盘需要重绘,所以的键的label被更新了,invalidateAllKeys() 方法用来重绘所有的键。
  • 对于 其他所有的codes,只是 简单的将unicode转化为字符并且发送到输入框里,如果这个code代表了字母表里的一个字母,并且caps变量为true,那么我们需要将字母转化为大写。

修改onKey的代码(这里的功能实现方法跟实例中有偏差):

@Overridepublic void onKey(int primaryCode, int[] keyCodes) {    InputConnection ic = getCurrentInputConnection();    playClick(primaryCode);    switch(primaryCode){    case Keyboard.KEYCODE_DELETE :        ic.deleteSurroundingText(1, 0);        break;    case Keyboard.KEYCODE_SHIFT:        caps = !caps;        keyboard.setShifted(caps);        kv.invalidateAllKeys();        break;    case Keyboard.KEYCODE_DONE:        ic.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));        break;    default:        char code = (char)primaryCode;        if(Character.isLetter(code) && caps){            code = Character.toUpperCase(code);        }        ic.commitText(String.valueOf(code),1);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

三、实例解析:继承EditText自定义view来实现

保证不遮挡输入框,界面漂亮有动画。数字键盘可随机,支持纯色绘制按键。

1. 效果图

Android 总结:自定义键盘实现原理和三种实例详解_第2张图片 
这个程序有点Bug,点击输入法最底部的三个键时,虚拟按键也触发到了。 
想解这个Bug的话自行再仔细研究下代码。

1. 功能特点

  1. 在输入时,保证键盘不会挡住输入框。
  2. 可以直接通过 Edittext 的属性来配置要显示的键盘布局 xml 文件。点击 Edittext 输入框即可弹出键盘。
  3. 支持属性配置 已经写好的键盘 xml 。支持属性配置 是否随机数字。
  4. 支持纯色绘制按键。默认的 keyboardview 在android2.3等低版本下不能正常显示纯色的按键背景。本示范工程通过重写原有的 keyboardview 来解决这个bug。

注:资源里面只有两种键盘样式:数字0-9+"000"0-9+. 。你可以通过自己写键盘布局xml,然后通过属性引用来显示自己的键盘。具体可以参考附件的示范工程。

2. 逻辑分析

1) 生成随机数的key

先for循环生成0-9的KeyModel,存储到LinkedList中

    LinkedList tempList = new LinkedList();    for (int i = 0; i < count; i++) {        tempList.add(new KeyModel(48 + i, i + ""));    }
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

后面通过随机数,从 LinkedList 中取出KeyModel放入新的 List 中(这里的代码是 resultList), 然后这里的 List 就是随机的了。

        Random rand = new SecureRandom();        rand.setSeed(SystemClock.currentThreadTimeMillis());        for (int i = 0; i < count; i++) {            int num = rand.nextInt(count - i);            // Log.d(TAG, " rand num"+num);            KeyModel model = tempList.get(num);            // Log.d(TAG, model.toString());            resultList.add(new KeyModel(model.getCode(), model.getLabel()));            tempList.remove(num);        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

四、实例解析:以Dialog的形式来实现

1. 效果图

Android 总结:自定义键盘实现原理和三种实例详解_第3张图片

2. 技术分析略。

五、源码下载地址:

  1. 在xml文件中定义:customkeyboard 下载

  2. 继承EditText自定义view来实现:customkeyboardbyedittext 下载

  3. 以Dialog的形式来实现:customkeyboardbydialog 下载

上面三种“自定义键盘”方式并非严格区分。

参考文章: 
1. Android创建自定义键盘(制作系统键盘而不只是应用的可以参考这个) 
2. Android自定义键盘示范工程,可直接在项目中使用

本博文转载自  http://blog.csdn.net/u014136472/article/details/50257245

本来想自己写的但是无意中发现这篇博客,感觉写的很好,所以就转载了。

如果需要对每一个例子的源码进行说明的话,可在评论出说明,我再自己写一些博文进行分析


更多相关文章

  1. Android 动态显示和隐藏软键盘
  2. edittext获取焦点并弹出软键盘
  3. Android里用代码设置View的相关属性
  4. Android应用程序键盘(Keyboard)消息处理机制分析(23)
  5. android 系统各种属性的获取
  6. 关于android软键盘隐藏总结
  7. Android 隐藏及切换显示键盘
  8. android点击空白处隐藏键盘(亲测)

随机推荐

  1. android开发中handler的总结
  2. Android输入系统概述
  3. Android之Adapter用法总结
  4. Android(安卓)UI开发专题(一) 之界面设计
  5. Android(安卓)9.0中sdcard 的权限和挂载
  6. Android(安卓)自定义view完全解析--带你
  7. Android(安卓)ViewDragHelper(1)
  8. Android(安卓)网络:Retrofit 与 Kotlin
  9. Eclipse 重装Android(安卓)ADT 问题~解决
  10. android 渗透测试必备工具