自定义View练习

来源:互联网 发布:mac桌面文件路径 编辑:程序博客网 时间:2024/05/28 06:05

自定义View练习 - 汉字键盘

练习来源

Android自定义键盘之汉字键盘

最终效果图

自定义键盘

基本知识

以下内容摘自上面的文章

一、软键盘介绍

实现软键盘主要用到了系统的两个类:Keyboard和KeyboardView。
Keyboard类源码的介绍是: Listener for virtual keyboard events.即用于监听虚拟键盘。
KeyboardView类源码的介绍是: A view that renders a virtual {@link Keyboard}. It handles rendering of keys and detecting key presses and touch movements.即它处理绘制键盘和检测按键和触摸动作。
它里面有很多方法,在我们自定义的软键盘很多属性,就需要我们用这个类来设置。比如:

keyboardView = (KeyboardView) act.findViewById(R.id.keyboard_view);  keyboardView.setKeyboard(k);  keyboardView.setEnabled(true);  keyboardView.setPreviewEnabled(true);keyboardView.setVisibility(View.VISIBLE);keyboardView.setOnKeyboardActionListener(listener);

了解一些源码,就可以是我们知道我们为什么要这样写,为什么要这样做了!

二、数字软键盘的布局

首先在res下新建xml文件夹,在xml文件夹中新建symbols.xml文件,这个布局文件主要是实现数字软键盘的布局,每一个按键都有一个codes值,在类中就是通过codes值来监听每一个按钮。

<?xml version="1.0" encoding="utf-8"?><Keyboard xmlns:android="http://schemas.android.com/apk/res/android"    android:keyWidth="20%p" android:horizontalGap="0px"    android:verticalGap="0px" android:keyHeight="@dimen/key_height">    <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="-5" android:keyIcon="@drawable/sym_keyboard_delete" />    </Row>    <Row>               <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="-2" android:keyLabel="中文" />    </Row>    <Row>               <Key android:codes="57" android:keyLabel="9" />        <Key android:codes="48" android:keyLabel="0" />        <Key android:codes="46" android:keyLabel="." />        <Key android:codes="-3" android:keyWidth="40%p"            android:isRepeatable="true" android:keyLabel="完成" />    </Row></Keyboard>

数字键盘界面如下:
数字键盘界面

在上面的键盘定义中,通过Keyboard说明是一个软键盘定义文件,Row元素说明这是一行按键的定义,Key元素说明这是一个按键的定义。Key元素通过一些属性来定义每个按键,下面是一些常用的属性介绍:
Codes:代表按键对应的输出值,可以为unicode值或者逗号(,)分割的多个值,也可以为一个字符串。在字符串中通过“\”来转义特殊字符,例如 ‘\n’ 或则 ‘\uxxxx’ 。Codes通常用来定义该键的键码,例如上图中的数字按键1对应的为49;如果提供的是逗号分割的多个值则和普通手机输入键盘一样在多个值之间切换。
keyLabel:代表按键显示的文本内容。
keyIcon:代表按键显示的图标内容,如果指定了该值则在显示的时候显示为图片不显示文本。
keyWidth:代表按键的宽度,可以为精确值或则相对值,对于精确值支持多种单位,例如:像素,英寸 等;相对值为相对于基础取值的百分比,为以% 或%p 结尾,其中%p表示相对于父容器。
keyHeight:代表按键的高度,取值同上。
horizontalGap:代表按键前的间隙(水平方向),取值同上。
isSticky:指定按键是否为sticky的。例如Shift大小写切换按键,具有两种状态,按下状态和正常状态,取值为true或者false。
isModifier:指定按键是否为功能键( modifier key ) ,例如 Alt 或者 Shift ,取值为true或false。
keyOutputText:指定按键输出的文本内容,取值为字符串。
isRepeatable:指定按键是否是可重复的,如果长按该键可以触发重复按键事件则为true,否则为false。
keyEdgeFlags:指定按键的对齐指令,取值为left或right。

我们在设置每一个按键的code时,就是根据keyboard类中定义的一些属性,比如回退,切换,完成等都是固定的。

  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;

知道了这些,我们就不会有太多的疑惑了!也是说,我们自定义的每一个按键都将会有一个codes值,比如回退我们就写成:

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

在监听处就是:

if (primaryCode == Keyboard.KEYCODE_DELETE){}

这就表示,监听回退事件了!

二、汉字键盘的codes的获得

每一个按键都有一个codes值,这个codes就是一个汉字在utf16标准中的编码值。

查找汉字的编码,有两种方法:
1,直接查找utf16表,可以参考:
http://blog.csdn.net/lintax/article/details/51866861
如果汉字个数比较多,需要将汉字与编码值一个个准确对应的键入xml中,也是一个挺费神的事情。
2,程序获得

    /**     * 生成xml文件中的codes和keyLabel     */    public static void main(String[] args) {        String[] names = {"赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈"};        char c;        int i;        for (String str : names) {            c = str.toCharArray()[0];            i = c;            System.out.println("<Key android:codes=\"" + i + "\" android:keyLabel=\"" + c + "\"/>");        }    }

生成的xml内容为:

<Key android:codes="36213" android:keyLabel="赵"/><Key android:codes="38065" android:keyLabel="钱"/><Key android:codes="23385" android:keyLabel="孙"/><Key android:codes="26446" android:keyLabel="李"/>

将这些获得的codes写到res/xml/chinese.xml文件中.
代码详见:
chinese.xml

三、示例的布局文件
一个EditText和一个隐藏的自定义键盘.

<?xml version="1.0" encoding="utf-8"?><RelativeLayout android:id="@+id/activity_main"                xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="match_parent">    <EditText        android:id="@+id/etContent"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:textColor="#333"/>    <android.inputmethodservice.KeyboardView        android:id="@+id/keyboardView"        android:layout_width="match_parent"        android:layout_height="200dp"        android:layout_alignParentBottom="true"        android:focusable="true"        android:focusableInTouchMode="true"        android:keyBackground="@drawable/keyboard_bg"        android:keyTextColor="#FFF"        android:keyPreviewLayout="@layout/key_preview_layout"        android:keyPreviewHeight="40dp"        android:visibility="gone"/></RelativeLayout>

注意这四个属性, 都能见名知意.

android:keyBackground="@drawable/keyboard_bg"android:keyTextColor="#FFF"android:keyPreviewLayout="@layout/key_preview_layout"android:keyPreviewHeight="40dp"

预览的布局key_preview_layout.xml内容为:

<?xml version="1.0" encoding="utf-8"?><TextView xmlns:android="http://schemas.android.com/apk/res/android"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:background="#ff8888ff"          android:gravity="center"          android:textColor="@android:color/white"          android:textSize="30dp"/>

四、使用自定义键盘
主要步骤
1. 将chinese.xml中codes绑定到keyboard上.
2. 设置keyboardview的属性
3. 设置OnKeyboardActionListener监听器. 主要实现onKey()和onPress()方法
4. 禁用系统的键盘和EditText的上下文菜单.
5. 实现EditText的onTouchListener监听器显示自定义键盘.

public class MainActivity extends AppCompatActivity {    private EditText etContent;    private KeyboardView keyboardView;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        etContent = (EditText) findViewById(R.id.etContent);        keyboardView = (KeyboardView) findViewById(R.id.keyboardView);        Keyboard chineseKeyboard = new Keyboard(this, R.xml.chinese);        keyboardView.setKeyboard(chineseKeyboard);        keyboardView.setEnabled(true);        keyboardView.setPreviewEnabled(true);        keyboardView.setOnKeyboardActionListener(listener);        //禁用系统自带的键盘        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {// api < 10            etContent.setInputType(InputType.TYPE_NULL);        } else {            this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);            try {                Class<EditText> cls = EditText.class;                Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);                setShowSoftInputOnFocus.setAccessible(true);                setShowSoftInputOnFocus.invoke(etContent, false);            } catch (Exception e) {                e.printStackTrace();            }        }        //禁用EditText的长按出现上下文菜单        etContent.setCustomSelectionActionModeCallback(new ActionMode.Callback() {            //在这里可以添加自己的菜单选项,再return true            @Override            public boolean onCreateActionMode(ActionMode mode, Menu menu) {                return false;//返回false表示屏蔽ActionMode菜单            }            @Override            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {                return false;            }            @Override            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {                return false;            }            @Override            public void onDestroyActionMode(ActionMode mode) {            }        });        //点击EditText弹出汉字键盘        etContent.setOnTouchListener(new View.OnTouchListener() {            @Override            public boolean onTouch(View view, MotionEvent motionEvent) {                showKeyboard();                return false;            }        });    }    public void showKeyboard() {        int visibility = keyboardView.getVisibility();        if (visibility == View.GONE || visibility == View.INVISIBLE) {            keyboardView.setVisibility(View.VISIBLE);        }    }    public void hideKeyboard() {        int visibility = keyboardView.getVisibility();        if (visibility == View.VISIBLE) {            keyboardView.setVisibility(View.GONE);        }    }    private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {        @Override        public void onPress(int primaryCode) {            //删除键和完成键不显示预览            if (primaryCode == Keyboard.KEYCODE_DELETE || primaryCode == Keyboard.KEYCODE_CANCEL) {                keyboardView.setPreviewEnabled(false);            } else { //其他键显示预览                keyboardView.setPreviewEnabled(true);            }        }        @Override        public void onRelease(int primaryCode) {        }        @Override        public void onKey(int primaryCode, int[] keyCodes) {            Editable editable = etContent.getText();            int start = etContent.getSelectionStart();//获得光标选中的开始位置            if (primaryCode == Keyboard.KEYCODE_CANCEL) { //完成                hideKeyboard();            } else if (primaryCode == Keyboard.KEYCODE_DELETE) {//退格                if (editable != null && editable.length() > 0) {                    if (start > 0) {                        editable.delete(start - 1, start);                    }                }            } else { //汉字键                editable.insert(start, Character.toString((char) primaryCode));            }        }        @Override        public void onText(CharSequence text) {        }        @Override        public void swipeLeft() {        }        @Override        public void swipeRight() {        }        @Override        public void swipeDown() {        }        @Override        public void swipeUp() {        }    };}

学习知识

  1. 自定义键盘的整个流程.
    (1) 获得需要的汉字Unicode,构成xml映射codes和Labels,作为显示的键;
    (2) 使用系统自带的KeyboardView作为键盘组件;
    (3) 绑定按键映射到Keyboard对象. 设置keyboardview属性. 设置预览布局;
    (4) 禁用系统键盘, 禁用EditText的上下文菜单;
    (5) 为keyboardView设置OnKeyboardActionListener监听器, 实现onKey()和onPress()方法;
    (6) 添加EditText的onTouchListener监听, 显示自定义键盘.

  2. 键盘内置了一些按键,这些按钮是不可更改的.

  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;

其他阅读文章:
Android自定义键盘之汉字键盘
自定义键盘实现原理和三种实例详解
android自定义键盘(解决弹出提示的字体颜色问题)
简单自定义安全键盘(只能输入字母,数字,部分符号)

github: https://github.com/cizkey/CustomPractice/tree/master/ChineseKeyboard

原创粉丝点击