Android创建自定义系统键盘
原文标题: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.InputMethod
action。
在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创建自定义系统键盘相关推荐
- android自定义系统键盘,Android自定义软键盘
[实例简介] Android自定义软键盘 [实例截图] [核心代码] keydemo └── keydemo ├── AndroidManifest.xml ├── bin │ ├── class ...
- 在iOS8 下用Swift 创建自定义的键盘
本文翻译自How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一个 ...
- [译] 用 Swift 创建自定义的键盘
本文翻译自 How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一 ...
- windows快捷键自定义_在Windows中创建自定义Windows键盘快捷键
windows快捷键自定义 Nearly everyone uses keyboard shortcuts of some sort on their Windows system but what ...
- Android怎么自定义布局,Android 创建自定义的布局
为可穿戴设备创建布局是和手持设备是一样的,除了我们需要为屏幕的尺寸和glanceability进行设计.但是不要期望通过搬迁手持应用的功能与UI到可穿戴上会有一个好的用户体验.仅仅在有需要的时候,我们 ...
- android 自定义安全键盘,android 实现自定义安全键盘 且每次数字随机变换位置
但是没有实现随机键盘 本次以该demo中的数字键盘为例 如何在每次打开键盘的时候都变换对应按键的位置 在设置自定义键盘keyboardView.setKeyboard(keyboard) 之前 随机排 ...
- Android自定义软键盘输入法,隐藏系统输入法显示光标的实现
android实现自定义软键盘,先上图看效果,效果基本上是仿ios输入法实现的 这里是实现隐藏系统输入法,同时让EditText能获取光标的代码部分(通过反射调用): <span style=& ...
- android自定义数字键盘和字母键盘,Android自定义键盘的实现(数字键盘和字母键盘)...
Android自定义键盘的实现(数字键盘和字母键盘) 发布时间:2020-09-04 03:18:48 来源:脚本之家 阅读:100 作者:浪淘沙xud 在项目中,产品对于输入方式会有特殊的要求,需要 ...
- android 自定义车牌键盘(kotlin)
android 自定义车牌键盘(kotlin) 前言 示例图 实现需求 定义键盘文件 核心代码 视频效果 汉字转化 项目链接 前言 平时停车缴费都要填车牌号码,就想着自己能不能也做个车牌键盘demo. ...
最新文章
- Verilog有符号数运算
- 关于键盘上方创建返回按钮
- centos7安装ftp_python 编译安装
- 计算机病毒的防治 教案,计算机病毒及防治教案
- java实验楼使用说明_Java 方法
- 谁是ASML的最大股东?为何荷兰光刻巨头要听美国的话?
- qt场景中视图QGraphicsView的缩放
- Ubuntu16.04在Wine-3.0平台安装最新版TIM(QQ),不折腾那些没用的!
- simulink与gt联合仿真问题求解
- 安卓控制新大陆云平台(二)
- C语言三种形式编九九乘法表,C语言九九乘法表(五种输出形式)
- 京东VS淘宝:待付款订单-再次支付方案对比
- 9.2 react受控组件和非受控组件
- 计算机系高考激励的句子,高考激励人心的句子及图片
- TP真阳性, FP假阳性, FN假阴性, TN真阴性
- 生产任务分配问题 matlab+lingo
- 文本分词并统计出现次数最高的几个词Python
- MFC 类层次结构图
- ARM嵌入式的定义和开发工具介绍
- 一行代码引发的集群服务宕掉的血案分析