Android创建自定义键盘

来源:互联网 发布:淘宝差评不显示怎么办 编辑:程序博客网 时间:2024/06/10 13:26

原文标题: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>

创建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>

编辑 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>

创建键盘布局

键盘的布局包含一个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"/>

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>

定义键盘的键

键盘上键的细节和它的位置我们指定在一个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,我们的键盘会有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>

你可能已经注意到了,有些键的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 InputMethodService    implements OnKeyboardActionListener{    private KeyboardView kv;    private Keyboard keyboard;    private boolean caps = false;    @Override    public void onKey(int primaryCode, int[] keyCodes) {    }    @Override    public void onPress(int primaryCode) {    }    @Override    public void onRelease(int primaryCode) {    }    @Override    public void onText(CharSequence text) {    }    @Override    public void swipeDown() {    }    @Override    public void swipeLeft() {    }    @Override    public void swipeRight() {    }    @Override    public void swipeUp() {    }}

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

@Overridepublic 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;}

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

最后,编辑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的代码,
@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);    }}

测试键盘

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

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

2 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 带的家教成绩没有提高怎么办 学生出国学校成绩证明怎么办 学生成绩考差了班主任怎么办 高一的学生成绩跟不上怎么办 综合素质评价手册丢了怎么办 小学综合素质评价手册丢了怎么办 人体质不出汗差怎么办 儿子一年级语文成绩太差怎么办 小孩读一年级差几个月怎么办 小孩一年级下学期数学差怎么办 小学五年成绩差怎么办 生完孩子记忆力不好怎么办 生了孩子之后记忆力不好怎么办 孩子记忆力差学习不好怎么办 党课结业证丢了怎么办 对三年级不听话的学生应该怎么办 素质报告单丢了怎么办 社保小红本丢了怎么办 小红本丢了怎么办 孩子小红本丢了怎么办 小学素质报告册丢了怎么办 小学生素质报告册丢了怎么办 高中素质报告册丢了怎么办 小升初素质报告单丢了怎么办? 三供一业移交后社区管理职能怎么办 初中政治总考不好怎么办 孩子上初一学习越来越差怎么办 胸经过整容后变得胸闷怎么办? 网瘾高中不学习怎么办 犯罪人逃到美国怎么办 10岁儿童偏胖怎么办 土地面积与实际面积不符怎么办 军转进省直单位双选失败怎么办 房改房楼龄到了70年怎么办 商品房房改房到70年后怎么办 公务员未享受房改政策怎么办 两套房改房违规怎么办 法院保全的物品在我家怎么办 西瓜视频答题结束了钱没提现怎么办 诚信答题密码忘了怎么办 我未成年杀了人怎么办