原文标题:Create A Custom Keyboard on Android

原文链接:http://code.tutsplus.com/tutorials/create-a-custom-keyboard-on-android–cms-22615

大部分Android设备没有物理键盘,作为代替,这些设备使用软键盘来接受用户输入,如果你对Android的个性化开发感兴趣,相信,创建一个自定义的软键盘会带你到另外一个全新的高度。 
利用Android SDK,你可以用很少的代码快速的创建一个软键盘,因为SDK负责了很多低水平的任务,例如识别键的touch事件、绘制键盘、在键盘和输入框之间建立联系。

预备知识

你需要eclipse ADT,不过建议使用Android studio[loader注]

创建一个新项目

创建一个新项目——SimpleKeyboard,保证你起了一个唯一的包名,minimum required SDK设置为Android 2.2,target SDK设置为Android 4.4。我们的项目没有activity,所以不需要选择Create Activity,点击finish。

编辑Manifest文件

软键盘被Android系统看作是Input Method Editor (IME),IME在AndroidManifest.xml中被定为为一个Service,并且 
需要使用BIND_INPUT_METHOD权限,并且添加android.view.InputMethodaction。 
在Application节点下添加一下代码,

<service android:name=".SimpleIME"android:label="@string/simple_ime"android:permission="android.permission.BIND_INPUT_METHOD"><meta-data android:name="android.view.im" android:resource="@xml/method"/><intent-filter><action android:name="android.view.InputMethod" /></intent-filter>
</service>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

创建method.xml

在上面的配置文件中service有一个meta-data引用了method.xml文件,没有这个文件,Android系统不会将我们的service视为一个有效的IME,这个文件包含了输入法和它的subtype的描述,对于我们的键盘,我们定义了一个单一的en_US英文键盘,如果你的项目中没有res/xml目录,创建它,并将method.xml添加到这个目录中,这个文件的内容如下,

<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android"><subtype
        android:label="@string/subtype_en_US"android:imeSubtypeLocale="en_US"android:imeSubtypeMode="keyboard" />
</input-method>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

编辑 strings.xml

我们需要三个string,如下

  • 我们APP的名称
  • 输入法的标签
  • 输入法子类的标签

strings.xml文件的内容如下,

<resources><string name="app_name">SimpleKeyboard</string><string name="simple_ime">Simple IME</string><string name="subtype_en_US">English (US)</string>
</resources>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

创建键盘布局

键盘的布局包含一个KeyboardView,layout_alignParentBottom=true 
属性保证我们的键盘总是出现在屏幕的底部。 
创建res/layout/keyboard.xml文件,并编辑它的内容如下,

<?xml version="1.0" encoding="UTF-8"?>
<android.inputmethodservice.KeyboardView
    xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/keyboard"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:keyPreviewLayout ="@layout/preview"
/>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

keyPreviewLayout指的是每当我们点击键盘上的某个键时,短暂弹出的布局。 
创建res/layout/preview.xml,它的内容如下,

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:background="#ffff00"android:textStyle="bold"android:textSize="30sp">
</TextView>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

定义键盘的键

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

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

例如,我们定义了一个字母A,codes属性的值是97,keyLabel 
属性的值就是A。如果一个code对应多个key,这个key代表的字符取决于这个key接受到的点击数taps)。 
例如,一个键具有63,33,58编码,

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

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

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

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

现在,我们开始定义键盘,创建res/xml/qwerty.xml文件,它的内容如下,

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"android:keyWidth="10%p"android:horizontalGap="0px"android:verticalGap="0px"  android:keyHeight="60dp"
><Row><Key android:codes="49" android:keyLabel="1" android:keyEdgeFlags="left"/><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" android:keyEdgeFlags="right"/></Row><Row><Key android:codes="113" android:keyLabel="q" android:keyEdgeFlags="left"/><Key android:codes="119" android:keyLabel="w"/><Key android:codes="101" android:keyLabel="e"/><Key android:codes="114" android:keyLabel="r"/><Key android:codes="116" android:keyLabel="t"/><Key android:codes="121" android:keyLabel="y"/><Key android:codes="117" android:keyLabel="u"/><Key android:codes="105" android:keyLabel="i"/><Key android:codes="111" android:keyLabel="o"/><Key android:codes="112" android:keyLabel="p" android:keyEdgeFlags="right"/></Row><Row><Key android:codes="97" android:keyLabel="a" android:keyEdgeFlags="left"/><Key android:codes="115" android:keyLabel="s"/><Key android:codes="100" android:keyLabel="d"/><Key android:codes="102" android:keyLabel="f"/><Key android:codes="103" android:keyLabel="g"/><Key android:codes="104" android:keyLabel="h"/><Key android:codes="106" android:keyLabel="j"/><Key android:codes="107" android:keyLabel="k"/><Key android:codes="108" android:keyLabel="l"/><Key android:codes="35,64" android:keyLabel="\# \@" android:keyEdgeFlags="right"/></Row><Row><Key android:codes="-1" android:keyLabel="CAPS" android:keyEdgeFlags="left"/><Key android:codes="122" android:keyLabel="z"/><Key android:codes="120" android:keyLabel="x"/><Key android:codes="99" android:keyLabel="c"/><Key android:codes="118" android:keyLabel="v"/><Key android:codes="98" android:keyLabel="b"/><Key android:codes="110" android:keyLabel="n"/><Key android:codes="109" android:keyLabel="m"/><Key android:codes="46" android:keyLabel="."/><Key android:codes="63,33,58" android:keyLabel="\? ! :" android:keyEdgeFlags="right"/></Row><Row android:rowEdgeFlags="bottom"><Key android:codes="44" android:keyLabel="," android:keyWidth="10%p"  android:keyEdgeFlags="left"/><Key android:codes="47" android:keyLabel="/" android:keyWidth="10%p" /><Key android:codes="32" android:keyLabel="SPACE" android:keyWidth="40%p" android:isRepeatable="true"/><Key android:codes="-5" android:keyLabel="DEL" android:keyWidth="20%p" android:isRepeatable="true"/><Key android:codes="-4" android:keyLabel="DONE" android:keyWidth="20%p" android:keyEdgeFlags="right"/></Row>
</Keyboard>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

你可能已经注意到了,有些键的code是负数,负数等于在Keyboard 
中预定义的常量,例如,-5等于Keyboard.KEYCODE_DELETE

创建Service

创建一个新的Java类,并命令为SimpleIME.java,这个类要继承自 
InputMethodService类并且实现OnKeyboardActionListener接口,OnKeyboardActionListener接口中的方法是在键盘上的键被点击或者按下时调用。 
SimpleIME类有三个成员变量,

  • KeyboardView 我们在layout中定义的view
  • Keyboard 分配到KeyboardView的实例
  • 一个boolean类型的值代表了caps lock是否可用

然后实现OnKeyboardActionListener中的方法,SimpleIME的代码如下,

public class SimpleIME extends InputMethodServiceimplements OnKeyboardActionListener{private KeyboardView kv;private Keyboard keyboard;private boolean caps = false;@Overridepublic void onKey(int primaryCode, int[] keyCodes) {}@Overridepublic void onPress(int primaryCode) {}@Overridepublic void onRelease(int primaryCode) {}@Overridepublic void onText(CharSequence text) {}@Overridepublic void swipeDown() {}@Overridepublic void swipeLeft() {}@Overridepublic void swipeRight() {}@Overridepublic void swipeUp() {}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

当键盘创建时,onCreateInputView方法会被调用,在这个方法中我们初始化那三个成员变量,onCreateInputView的代码如下,

@Override
public View onCreateInputView() {kv = (KeyboardView)getLayoutInflater().inflate(R.layout.keyboard, null);keyboard = new Keyboard(this, R.xml.qwerty);kv.setKeyboard(keyboard);kv.setOnKeyboardActionListener(this);return kv;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

接下来,我们创建一个方法,这个方法的作用就是当我们按下某个键时发出一个声音,我们使用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

最后,编辑onKey方法,以便我们的输入法可以和其他应用程序的输入框交互,getCurrentInputConnection方法可以获取我们输入法与其他应用程序的连接,当我们获取到了连接,我们可以使用以下方法,

  • commitText 可以往编辑框里添加一个或多个字符
  • deleteSurroundingText 可以删除编辑框里一个多个字符
  • sendKeyEvent 可以发送事件到其他应用程序,例如KEYCODE_ENTER

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

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

测试键盘

我们的键盘现在可以测试了,将我们的程序运行到android设备上,这个应用没有activity,这意味着我们的应用不会出现在launcher里,要使用它,我们需要在设置里激活它

激活Simple IME后,打开任意一个有输入框的应用(例如,消息),点击输入框,在通知栏你会看到输入法的图片,依赖你的设备,你可以点击图标或者拉下通知栏选择Simple IME作为输入法,现在你可以用你的新输入法输入内容啦。

/~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~&~/

注意:

经过操作,使用Android Studio开发时,必须要写一个Activity,没有Activity的时候无法调试demo,会报错。

Android创建自定义系统键盘相关推荐

  1. android自定义系统键盘,Android自定义软键盘

    [实例简介] Android自定义软键盘 [实例截图] [核心代码] keydemo └── keydemo ├── AndroidManifest.xml ├── bin │   ├── class ...

  2. 在iOS8 下用Swift 创建自定义的键盘

    本文翻译自How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一个 ...

  3. [译] 用 Swift 创建自定义的键盘

    本文翻译自 How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一 ...

  4. windows快捷键自定义_在Windows中创建自定义Windows键盘快捷键

    windows快捷键自定义 Nearly everyone uses keyboard shortcuts of some sort on their Windows system but what ...

  5. Android怎么自定义布局,Android 创建自定义的布局

    为可穿戴设备创建布局是和手持设备是一样的,除了我们需要为屏幕的尺寸和glanceability进行设计.但是不要期望通过搬迁手持应用的功能与UI到可穿戴上会有一个好的用户体验.仅仅在有需要的时候,我们 ...

  6. android 自定义安全键盘,android 实现自定义安全键盘 且每次数字随机变换位置

    但是没有实现随机键盘 本次以该demo中的数字键盘为例 如何在每次打开键盘的时候都变换对应按键的位置 在设置自定义键盘keyboardView.setKeyboard(keyboard) 之前 随机排 ...

  7. Android自定义软键盘输入法,隐藏系统输入法显示光标的实现

    android实现自定义软键盘,先上图看效果,效果基本上是仿ios输入法实现的 这里是实现隐藏系统输入法,同时让EditText能获取光标的代码部分(通过反射调用): <span style=& ...

  8. android自定义数字键盘和字母键盘,Android自定义键盘的实现(数字键盘和字母键盘)...

    Android自定义键盘的实现(数字键盘和字母键盘) 发布时间:2020-09-04 03:18:48 来源:脚本之家 阅读:100 作者:浪淘沙xud 在项目中,产品对于输入方式会有特殊的要求,需要 ...

  9. android 自定义车牌键盘(kotlin)

    android 自定义车牌键盘(kotlin) 前言 示例图 实现需求 定义键盘文件 核心代码 视频效果 汉字转化 项目链接 前言 平时停车缴费都要填车牌号码,就想着自己能不能也做个车牌键盘demo. ...

最新文章

  1. Verilog有符号数运算
  2. 关于键盘上方创建返回按钮
  3. centos7安装ftp_python 编译安装
  4. 计算机病毒的防治 教案,计算机病毒及防治教案
  5. java实验楼使用说明_Java 方法
  6. 谁是ASML的最大股东?为何荷兰光刻巨头要听美国的话?
  7. qt场景中视图QGraphicsView的缩放
  8. Ubuntu16.04在Wine-3.0平台安装最新版TIM(QQ),不折腾那些没用的!
  9. simulink与gt联合仿真问题求解
  10. 安卓控制新大陆云平台(二)
  11. C语言三种形式编九九乘法表,C语言九九乘法表(五种输出形式)
  12. 京东VS淘宝:待付款订单-再次支付方案对比
  13. 9.2 react受控组件和非受控组件
  14. 计算机系高考激励的句子,高考激励人心的句子及图片
  15. TP真阳性, FP假阳性, FN假阴性, TN真阴性
  16. 生产任务分配问题 matlab+lingo
  17. 文本分词并统计出现次数最高的几个词Python
  18. MFC 类层次结构图
  19. ARM嵌入式的定义和开发工具介绍
  20. 一行代码引发的集群服务宕掉的血案分析

热门文章

  1. 无需公网IP,在家使用IPV6和电信光猫进行内网穿透以搭建远程主机
  2. 2019年上半年信息安全工程师上午选择题及解析
  3. yii2 连接mysql_yii2连接多个数据库教程
  4. Maven仓库的下载安装流程
  5. 老机器在当下该装什么操作系统
  6. Open3d系列 | 2. Open3d实现点云数据增强
  7. 计算机美术设计基础说课教案,教材教案_美术设计基础教案.doc
  8. Java开发自学技巧!中原银行java开发
  9. 大数据技术之Scala
  10. Android9及以上后台应用无法获取麦克风权限问题