自定义全键盘-[Android_YangKe]

尊重劳动者创作,转发请注明出处

首先看本文实现的效果。

yangke.gif

学而不思则罔,思而不学则殆。一眨眼五一小长假就结束了,完全没玩嗨呢,不能完全进入工作状态,小伙伴们扶我起来嗨。一年嗨两次,一次嗨半年。好了,言归正传,今天是一个自定义键盘。

首先了解 API

  • KeyboardView
  • Keyboard

KeyboardView

KeyboardView 一个用于呈现虚拟键盘的 view,同时处理着每一个键盘所对应的点击、触摸等事件。

常用属性:

XML attributes
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.

顾名思义这些 API 很简单,这里不做过多的解释。在使用时我们需要特别注意下 android:verticalCorrection 。由于 android 设备众多,键盘 y 轴触摸区域可能存在偏差,此 API 是用于矫正偏移的 Y 坐标。具体作用自己可以在 xml 手动更改进行感受。

Keyboard

Keyboard 的样式是以 XML 文件的形式存在的,由多个 Row 和 Key 组成,我们可以直接在 XML 定义键盘的行、键、以及键大小,下面看代码块。

 <Keyboard
     android:keyWidth="%10p"
     android:keyHeight="50px"
     android:horizontalGap="2px"
     android:verticalGap="2px" >
 <Row android:keyWidth="32px" >
     <Key android:keyLabel="A" />
     ...
 </Row>
 ...
 </Keyboard>

其中 Keyboard 表示整个键盘, Row 表示其中一行,Key 表示某一个具体按键。也就是说键盘的大小,样式都可以在这个文件中进行定义,下面通过一个表格对 Keyboard 必要属性进行简单了解。

XML attributes
android:horizontalGap Default horizontal gap between keys.
android:keyHeight Default height of a key, in pixels or percentage of display width.
android:keyWidth Default width of a key, in pixels or percentage of display width.
android:verticalGap Default vertical gap between rows of keys.

OK,到这里自定义键盘所需要了解的知识已经足够了,下面进入编码模式。

public class KeyboardViewS implements OnKeyboardActionListener {

private static final int KEYBOARD_DURATION = 350;
private EditText mEditText;
private Keyboard mKeyboard;
/** 是否大写 */
private boolean isUperCase = false;
private android.inputmethodservice.KeyboardView keyboardView;

public KeyboardViewS(Activity act, EditText edit) {
    this.mEditText = edit;
    mKeyboard = new Keyboard(act, R.xml.qwerty);

    keyboardView = (android.inputmethodservice.KeyboardView) (act.findViewById(R.id.keyboard_view));
    keyboardView.setKeyboard(mKeyboard);
    /** 设置没有弹窗的提示 */
    keyboardView.setPreviewEnabled(false);
    keyboardView.setOnKeyboardActionListener(this);
    uperCase();
}

@Override
public void onKey(int primaryCode, int[] keyCodes) {
    Editable editable = mEditText.getText();
    int start = mEditText.getSelectionStart();
    if (primaryCode == Keyboard.KEYCODE_CANCEL) {       // 完成
        hideKeyboard(keyboardView);
    } else if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
        if (editable != null && editable.length() > 0) {
            if (start > 0) {
                editable.delete(start - 1, start);
            }
        }
    } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {// 大小写切换
        uperCase();
        keyboardView.setKeyboard(mKeyboard);
    } else if (primaryCode == 57419) {
        if (start > 0) {
            mEditText.setSelection(start - 1);
        }
    } else if (primaryCode == 57421) {
        if (start < mEditText.length()) {
            mEditText.setSelection(start + 1);
        }
    } else {
        editable.insert(start, Character.toString((char) primaryCode));
    }
}

/** 键盘大小写切换 */
private void uperCase() {
    final List<Key> keylist = mKeyboard.getKeys();
    if (isUperCase) {
        isUperCase = false;
        for (Key key : keylist) {
            if (key.label != null && isword(key.label.toString())) {
                key.label = key.label.toString().toLowerCase();
                key.codes[0] = key.codes[0] + 32;
            }
        }
    } else {
        isUperCase = true;
        for (Key key : keylist) {
            if (key.label != null && isword(key.label.toString())) {
                key.label = key.label.toString().toUpperCase();
                key.codes[0] = key.codes[0] - 32;
            }
        }
    }
}

/** 隐藏输入法,显示光标 */
public static  void setSystemInputGone(EditText editText) {
    if (Build.VERSION.SDK_INT >= 11) {
        Class<EditText> cls = EditText.class;
        try {
            Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
            setShowSoftInputOnFocus.setAccessible(false);
            setShowSoftInputOnFocus.invoke(editText, false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        editText.setInputType(android.text.InputType.TYPE_NULL);
        editText.setInputType(editText.getInputType());
    }
}

/** 显示键盘 */
public void showKeyboard() {
    int visibility = keyboardView.getVisibility();
    if (visibility == View.GONE || visibility == View.INVISIBLE) {
        Animation anim = AnimationUtils.translateAnimationOut(KEYBOARD_DURATION);
        keyboardView.setVisibility(View.VISIBLE);
        keyboardView.startAnimation(anim);
        anim.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationEnd(Animation animation) {
                super.onAnimationEnd(animation);
                keyboardView.clearAnimation();
            }
        });
    }
}

/** 隐藏键盘 */
public static void hideKeyboard(final KeyboardView keyboardView) {
    if (keyboardView == null) {
        return;
    }
    if (keyboardView.getVisibility() == View.VISIBLE) {
        Animation anim = AnimationUtils.translateAnimationIn(KEYBOARD_DURATION);
        keyboardView.startAnimation(anim);
        anim.setAnimationListener(new AnimationListener() {
            @Override
            public void onAnimationEnd(Animation animation) {
                super.onAnimationEnd(animation);
                keyboardView.clearAnimation();
            }
        });
        keyboardView.setVisibility(View.GONE);
    }
}

private boolean isword(String str) {
    final String wordstr = "abcdefghijklmnopqrstuvwxyz";
    if (wordstr.indexOf(str.toLowerCase()) > -1) {
        return true;
    }
    return false;
}
...
}

核心代码。尊重劳动者成功,转发请注明出处。

<?xml version="1.0" encoding="UTF-8"?>
<Keyboard android:keyWidth="8.4%" android:keyHeight="7%"
android:horizontalGap="5dp" android:verticalGap="3dp"
xmlns:android="http://schemas.android.com/apk/res/android">

<Row>
    <Key android:codes="49" android:keyLabel="1" />
    <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:keyEdgeFlags="right" android:keyLabel="0" />
</Row>

<Row>
    <Key android:codes="113" android:keyEdgeFlags="left" android:keyLabel="q" />
    <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:keyEdgeFlags="right" android:keyLabel="p" />
</Row>

<Row>
    <Key android:horizontalGap="6%p" android:codes="97" android:keyEdgeFlags="left" android:keyLabel="a" />
    <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:keyEdgeFlags="right" android:keyLabel="l" />
</Row>

<Row>
    <Key android:keyWidth="13%p" android:codes="-1" android:keyEdgeFlags="left" android:isModifier="true" android:isSticky="true" android:keyIcon="@drawable/shift" />
    <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:keyWidth="13.3%p" android:codes="-5" android:keyEdgeFlags="right" android:isRepeatable="true" android:keyIcon="@drawable/keyboard_delete" />
</Row>

<Row android:rowEdgeFlags="bottom">
    <Key android:keyWidth="15%p" android:codes="-6" android:keyLabel="复制"/>
    <Key android:keyWidth="15%p" android:codes="-6" android:keyLabel="粘贴"/>
    <Key android:keyWidth="44%p" android:codes="32" android:isRepeatable="true" android:keyLabel="~~ 杨柯 ~~" />
    <Key android:keyWidth="17.5%p" android:codes="-3" android:keyEdgeFlags="right" android:keyLabel="完成" />
</Row>

</Keyboard>

再坚持一下,再努力一下,再前进一下,也许,成功离你只有一步之遥。有句话说,哪怕只有百分之一的希望,我也要付出百分之百的努力。学习不能停!!



** ps: 有帮助的话: 喜欢、评论、转发,动一动你的小手让更多的人知道!关注 帅比-杨**

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,598评论 25 707
  • 好久没有写Android的文章了,有两三个月多了吧,刚开始搞微信小程序,后来又开搞ReactNative,现在又兴...
    Code4Android阅读 17,523评论 4 26
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,115评论 2 44
  • 这些天我总是做梦 梦里我们回到了从前 你会趁我不注意的时候突然跑开 躲在一旁偷看我寻扎你时的慌张神态 然后突然出现...
    陈乡阅读 257评论 0 0
  • 一,基本运算符 1.赋值运算符/Assignment Operator ("=") 与OC不同的是,可以一次赋多个...
    kodbin阅读 205评论 0 0