android 自定义键盘的简单实现和遇到的问题

参考网站:

自定义软键盘(Android)_Wing_LS的博客-CSDN博客

Android自定义键盘的简单实现_xyTianZhao的博客-CSDN博客_android自定义键盘

Dialog上的EditText的自定义键盘_SKY_L1的博客-CSDN博客

Android 4.0设置Dialog点击屏幕不消失_一叶飘舟的博客-CSDN博客

一、代码实现

参考Android 4.0设置Dialog点击屏幕不消失_一叶飘舟的博客-CSDN博客的文章基本可以完成软键盘的展示,对其调整后代码如下:

KeyboardUtil
package xxx.xxx.xxx.softKeyboard;

import android.content.Context;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.text.Editable;
import android.view.View;
import android.widget.EditText;

import xxx.xxx.xxx.R;
import xxx.xxx.xxx.util.LogUtils;

import java.util.List;

public class KeyboardUtil {

        private Context context;
        private KeyboardView keyboardView;
        private Keyboard kQwerty;//字母键盘
        private Keyboard kSymbols;//符号键盘
        private boolean isNum = false;//是否是数字
        private boolean isSupper = false;//是否大写
        private EditText editText;
        private boolean isShown = false;

        /**
         * 构造方法
         *
         * @param context  上下文
         * @param editText 需要输入的EditView
         * @param pView    KeyboardView所在的父控件
         */
        public KeyboardUtil(Context context, EditText editText, View pView) {
            this.context = context;
            this.editText = editText;
            //创建字母和符号键盘
            kQwerty = new Keyboard(context, R.xml.qwenty);
            kSymbols = new Keyboard(context, R.xml.symbols);
            //找到KeyboardView
            this.keyboardView = (KeyboardView) pView
                    .findViewById(R.id.keyboard_view);
            this.keyboardView.setKeyboard(kQwerty);
            this.keyboardView.setEnabled(true);
            this.keyboardView.setPreviewEnabled(false);
            this.keyboardView.setOnKeyboardActionListener(listener);
        }

        //Keyboard监听
        KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {

            @Override
            public void swipeUp() {
                // TODO Auto-generated method stub

            }

            @Override
            public void swipeRight() {
                // TODO Auto-generated method stub

            }

            @Override
            public void swipeLeft() {
                // TODO Auto-generated method stub

            }

            @Override
            public void swipeDown() {
                // TODO Auto-generated method stub

            }

            @Override
            public void onText(CharSequence text) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onRelease(int primaryCode) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onPress(int primaryCode) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onKey(int primaryCode, int[] keyCodes) {
                //Toast.makeText(context, "onKey--"+primaryCode,
                // Toast.LENGTH_LONG).show();
                //LogUtils.e("=4=","onKey:" + primaryCode);
                Editable editable = editText.getText();
                int start = editText.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 if (primaryCode == Keyboard.KEYCODE_SHIFT) {
                    // 大小写切换
                    changeKey();
                    keyboardView.setKeyboard(kQwerty);
                } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
                    ((CKeyboardView) keyboardView).setLastKeyIndex(0);
                    // 数字键盘切换
                    if (isNum) {
                        keyboardView.setKeyboard(kQwerty);
                    } else {
                        keyboardView.setKeyboard(kSymbols);
                    }
                    isNum = !isNum;
                } else {
                    editable.insert(start, Character.toString((char) primaryCode));
                }

            }
        };

        public KeyboardView getKeyboardView() {
            return keyboardView;
        }

        public EditText getEditText() {
            return editText;
        }

        public void setEditText(EditText editText) {
            this.editText = editText;
        }

        //变换大小写
        private void changeKey() {
            List<Keyboard.Key> keys = kQwerty.getKeys();

            for (Keyboard.Key key : keys) {
                if (key.label != null && isWord(String.valueOf(key.label))) {
                    if (isSupper) {// up to low
                        key.label = key.label.toString().toLowerCase();
                        key.codes[0] = key.codes[0] + 32;
                    } else {
                        key.label = key.label.toString().toUpperCase();
                        key.codes[0] = key.codes[0] - 32;
                    }
                }
            }

            isSupper = !isSupper;

        }

        private boolean isWord(String s) {
            String reg = "[a-zA-Z]{1}";
            return s.matches(reg);
        }
        //显示键盘
        public void showKeyboard() {
            int visibility = keyboardView.getVisibility();
            if (visibility == View.GONE || visibility == View.INVISIBLE) {
                keyboardView.setVisibility(View.VISIBLE);
                setShown(true);
            }
        }
        //隐藏键盘
        public void hideKeyboard() {
            if (keyboardView.getVisibility() == View.VISIBLE) {
                keyboardView.setVisibility(View.GONE);
                setShown(false);
            }
        }

        public boolean isShown() {
            return isShown;
        }

        public void setShown(boolean isShown) {
            this.isShown = isShown;
        }
}
CKeyboardView
package xxx.xxx.xxx.softKeyboard;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.AttributeSet;
import android.view.KeyEvent;

import java.util.ArrayList;
import java.util.List;

public class CKeyboardView extends KeyboardView {

    private Keyboard currentKeyboard;
    private List<Keyboard.Key> keys = new ArrayList<Keyboard.Key>();
    private int lastKeyIndex = 0;
    private Keyboard.Key focusedKey;//当前获取焦点的key
    private Rect rect;//表示包裹当前获取焦点的key的方框

    private int nCurKeyboardKeyNums;//当前键盘的按键数量
    private Keyboard nCurrentKeyboard;
    private List<Keyboard.Key> nKeys;//按键集合
    private int nLastKeyIndex = 0;

    @Override
    public void setKeyboard(Keyboard keyboard) {
        super.setKeyboard(keyboard);
    }

    public CKeyboardView(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    public void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        //获取当前键盘
        currentKeyboard = this.getKeyboard();
        keys = currentKeyboard.getKeys();
        //当前获取焦点的key画方框,表示选中的是当前key
        /*Paint p = new Paint();
        p.setColor(Color.parseColor("#33ffff"));
        p.setStyle(Paint.Style.STROKE);
        p.setStrokeWidth(3.75f);
        focusedKey = keys.get(lastKeyIndex);
        rect = new Rect(focusedKey.x, focusedKey.y + 4, focusedKey.x
                + focusedKey.width, focusedKey.y + focusedKey.height);
        canvas.drawRect(rect, p);*/
    }

    public int getLastKeyIndex() {
        return lastKeyIndex;
    }

    public void setLastKeyIndex(int lastKeyIndex) {
        this.lastKeyIndex = lastKeyIndex;
    }

    private void setFields() {
        nCurrentKeyboard = this.getKeyboard();
        nKeys = nCurrentKeyboard.getKeys();
        nCurKeyboardKeyNums = nKeys.size();
        nLastKeyIndex = this.getLastKeyIndex();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        //Toast.makeText(this.getContext(), "onKeyDown--"+keyCode, Toast.LENGTH_LONG).show();
        //Log.d("tag", keyCode + "---" + event.getAction());
        switch (keyCode) {
            case KeyEvent.KEYCODE_BACK:// 返回 4
                if (event.getRepeatCount() == 0) {
                    if (this.handleBack()) {
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_DPAD_DOWN:// 向下 20
                setFields();

                if (nLastKeyIndex >= nCurKeyboardKeyNums - 1) {
                    this.setLastKeyIndex(0);
                } else {
                    int x = nKeys.get(nLastKeyIndex).x;
                    int y = nKeys.get(nLastKeyIndex).y;
                    int[] nearestKeys = nCurrentKeyboard.getNearestKeys(x, y);

                    for (int index : nearestKeys) {
                        if (nLastKeyIndex < index) {
                            Keyboard.Key nearKey = nKeys.get(index);
                            Keyboard.Key lastKey = nKeys.get(nLastKeyIndex);
                            if (((lastKey.x >= nearKey.x) // left side compare
                                    && (lastKey.x < (nearKey.x + nearKey.width)))
                                    || (((lastKey.x + lastKey.width) > nearKey.x) // right
                                    // side
                                    // compare
                                    && ((lastKey.x + lastKey.width) <= (nearKey.x + nearKey.width)))) {
                                this.setLastKeyIndex(index);
                                break;
                            }
                        }
                    }

                }
                this.invalidate();
                return true;
            case KeyEvent.KEYCODE_DPAD_UP:// 向上19
                setFields();

                if (nLastKeyIndex <= 0) {
                    this.setLastKeyIndex(nCurKeyboardKeyNums - 1);
                } else {
                    int x = nKeys.get(nLastKeyIndex).x;
                    int y = nKeys.get(nLastKeyIndex).y;
                    int[] nearestKeys = nCurrentKeyboard.getNearestKeys(x, y);

                    for (int i = nearestKeys.length - 1; i >= 0; i--) {
                        int index = nearestKeys[i];
                        if (nLastKeyIndex > index) {
                            Keyboard.Key nearKey = nKeys.get(index);
                            Keyboard.Key nextNearKey = nKeys.get(index + 1);
                            Keyboard.Key lastKey = nKeys.get(nLastKeyIndex);
                            if ((lastKey.x >= nearKey.x && lastKey.x < (nearKey.x + nearKey.width))
                                    && ((lastKey.x + lastKey.width) <= (nextNearKey.x + nextNearKey.width) || lastKey.x
                                    + lastKey.width > nextNearKey.x)) {
                                this.setLastKeyIndex(index);
                                break;
                            }
                        }
                    }
                }
                this.invalidate();
                return true;
            case KeyEvent.KEYCODE_DPAD_LEFT:// 左21
                setFields();

                if (nLastKeyIndex <= 0) {
                    this.setLastKeyIndex(nCurKeyboardKeyNums - 1);
                } else {
                    nLastKeyIndex--;
                    this.setLastKeyIndex(nLastKeyIndex);
                }
                this.invalidate();
                return true;
            case KeyEvent.KEYCODE_DPAD_RIGHT:// 右22

                setFields();
                if (nLastKeyIndex >= nCurKeyboardKeyNums - 1) {
                    this.setLastKeyIndex(0);
                } else {
                    nLastKeyIndex++;
                    this.setLastKeyIndex(nLastKeyIndex);
                }
                this.invalidate();
                return true;
            case KeyEvent.KEYCODE_ENTER://66
            case KeyEvent.KEYCODE_DPAD_CENTER://23
                setFields();
                int currentKeyCode = nKeys.get(nLastKeyIndex).codes[0];

                switch (currentKeyCode) {
                    case Keyboard.KEYCODE_MODE_CHANGE:
                    case Keyboard.KEYCODE_CANCEL:
                    case Keyboard.KEYCODE_DELETE:
                    case Keyboard.KEYCODE_SHIFT:
                        getOnKeyboardActionListener().onKey(currentKeyCode, null);
                        return true;

                    default:
                        getOnKeyboardActionListener().onKey(currentKeyCode, null);
                        return true;
                }
        }
        return super.onKeyDown(keyCode, event);
    }
}

qwenty.xml

<?xml version="1.0" encoding="UTF-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0.0px"
    android:keyHeight="8%"
    android:keyWidth="10.000002%p"
    android:verticalGap="0.0px">

    <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:codes="97"
            android:horizontalGap="4.999995%p"
            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:codes="-1"
            android:isModifier="true"
            android:isSticky="true"
            android:keyEdgeFlags="left"
            android:keyIcon="@mipmap/icon_s_top"
            android:keyWidth="14.999998%p" />

        <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="-5"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyIcon="@mipmap/icon_s_delete"
            android:keyWidth="14.999998%p" />

    </Row>

    <Row android:rowEdgeFlags="bottom">

        <Key
            android:codes="-2"
            android:keyLabel="12#"
            android:keyWidth="20.000004%p" />

        <Key
            android:codes="44"
            android:keyLabel=","
            android:keyWidth="14.999998%p" />

        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyIcon="@mipmap/icon_space"
            android:keyWidth="29.999996%p" />

        <Key
            android:codes="46"
            android:keyLabel="."
            android:keyWidth="14.999998%p" />

        <Key
            android:codes="-3"
            android:keyEdgeFlags="right"
            android:keyLabel="完成"
            android:keyWidth="20.000004%p" />
    </Row>

</Keyboard>

symbols.xml

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="0px"
    android:keyHeight="8%"
    android:keyWidth="10%p"
    android:verticalGap="0px" >

    <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:keyLabel="0" />
    </Row>

    <Row>
        <Key
            android:codes="64"
            android:keyIcon="@mipmap/icon_aite" />
        <Key
            android:codes="35"
            android:keyLabel="#" />
        <Key
            android:codes="36"
            android:keyLabel="$" />
        <Key
            android:codes="37"
            android:keyLabel="%" />
        <Key
            android:codes="38"
            android:keyIcon="@mipmap/icon_yu"
             />
        <Key
            android:codes="42"
            android:keyLabel="*" />
        <Key
            android:codes="45"
            android:keyLabel="-" />
        <Key
            android:codes="61"
            android:keyLabel="=" />
        <Key
            android:codes="40"
            android:keyLabel="(" />
        <Key
            android:codes="41"
            android:keyLabel=")" />
    </Row>
    <Row>
        <Key
            android:codes="95"
            android:keyLabel="_" />
        <Key
            android:codes="33"
            android:keyLabel="!" />
        <Key
            android:codes="34"
            android:keyIcon="@mipmap/icon_shuang1"/>
        <Key
            android:codes="39"
            android:keyLabel="'" />
        <Key
            android:codes="58"
            android:keyLabel=":" />
        <Key
            android:codes="59"
            android:keyLabel=";" />
        <Key
            android:codes="47"
            android:keyLabel="/" />
        <Key
            android:codes="63"
            android:keyIcon="@mipmap/icon_wenhao"/>
        <Key
            android:codes="43"
            android:keyLabel="+" />
        <Key
            android:codes="-5"
            android:isRepeatable="true"
            android:keyEdgeFlags="right"
            android:keyIcon="@mipmap/icon_s_delete"
            />
    </Row>
    <Row android:rowEdgeFlags="bottom" >
        <Key
            android:codes="-2"
            android:keyLabel="ABC"
            android:keyWidth="20%p" />

        <Key
            android:codes="60"
            android:keyIcon="@mipmap/icon_xiao"
            android:keyWidth="12%p"/>

        <Key
            android:codes="62"
            android:keyIcon="@mipmap/icon_da"
            android:keyWidth="12%p" />
        <Key
            android:codes="32"
            android:isRepeatable="true"
            android:keyIcon="@mipmap/icon_space"
            android:keyWidth="12%p"  />

        <Key
            android:codes="44"
            android:keyLabel=","
            android:keyWidth="12%p"/>
        <Key
            android:codes="46"
            android:keyLabel="."
            android:keyWidth="12%p" />

        <Key
            android:codes="-3"
            android:keyEdgeFlags="right"
            android:keyLabel="完成"
            android:keyWidth="20%p" />
    </Row>

</Keyboard>

其中键盘上有些字符无法使用字符串展示,只能使用图片展示,可自行设计如(@,&,>,",删除键,切换大小写键,切换数字和字母键,空格键)

二、如何使用

在需要使用的activity对应的xml文件中加入

<RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >

        <xxx.xxx.xxx.softKeyboard.CKeyboardView
            android:id="@+id/keyboard_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:focusableInTouchMode="true"
            android:visibility="gone"
            />

        <!--android:keyTextColor="@android:color/white"
        android:background="@mipmap/login_bgc"


        android:background="@mipmap/bg_keyboard"
            android:keyBackground="@mipmap/bg_keyboard"
        -->
    </RelativeLayout>

其中:

android:background="@mipmap/bt_background_active"  设置键盘背景
android:keyBackground="@mipmap/bt_background_active"  设置按键背景
android:keyTextColor="@color/black"  设置按键文字颜色
android:shadowColor="@color/white"  设置按键文字阴影颜色
android:shadowRadius="0"  设置阴影半径

因为我们的需求是隐藏按键的动态效果,因此加入了以上的属性。

在对应的EditText加上监听让点击后自定义键盘显示,代码如下:

passwordEditText = findViewById(R.id.password);
        passwordEditText.setTransformationMethod(new MyTransformation());//可以隐藏密码输入类型时,短暂按键值的显示

        
        passwordEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean b) {
                keyboardUtil.setEditText(passwordEditText);
                keyboardUtil.showKeyboard();
            }
        });
MyTransformation,这个可以根据需要进行自行设定
package xxx.xxx.xxx.ui.other;

import android.text.method.PasswordTransformationMethod;
import android.view.View;

public class MyTransformation extends PasswordTransformationMethod {

    @Override
    public CharSequence getTransformation(CharSequence source, View view) {
        return new PasswordCharSequence(source);
    }

    private class PasswordCharSequence implements CharSequence {
        private CharSequence mSource;

        public PasswordCharSequence(CharSequence source) {
            mSource = source; // Store char sequence
        }

        public char charAt(int index) {
            return '*'; // This is the important part
        }

        public int length() {
            return mSource.length(); // Return default
        }

        public CharSequence subSequence(int start, int end) {
            return mSource.subSequence(start, end); // Return default
        }
    }

}

以上就完成了简单的自定义键盘的使用。

三、遇到的问题

1,软键盘的关闭,当点击键盘和输入框以外的地方需要隐藏软键盘,代码如下:

//隐藏软键盘,输入框失去焦点
    public void hideSoftKeyboard()
    {
        LogUtils.e("=1=","2222222222222222");
        usernameEditText.clearFocus();
        passwordEditText.clearFocus();
        //Hides the SoftKeyboard
        View view = this.getWindow().getDecorView();
        //系统软件盘的关闭
        InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0); //强制隐藏键盘
        //自定义键盘
        keyboardUtil.hideKeyboard();
    }

    /**
     * 关闭EditText以外的任何地方的SoftKeyboard onTouch
     * @param view
     */
    public void setupUI(View view)
    {
        if (!(view instanceof EditText || view instanceof CKeyboardView)) {
            view.setOnTouchListener(new View.OnTouchListener() {
                public boolean onTouch(View v, MotionEvent event) {
                    hideSoftKeyboard();
                    return false;
                }
            });
        }

        //If a layout container, iterate over children and seed recursion.
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                View innerView = ((ViewGroup) view).getChildAt(i);
                setupUI(innerView);
            }
        }
    }

在activity的onCreate方法中调用setupUI即可。

2.当fragment中需要使用软键盘,需要其activity的xml中加入软键盘的布局代码片段,然后再activity中定义keyboardUtil,然后再通过fragment的构造函数传递到其中,然后再在fragment使用,同样在activity和fragment中调用隐藏代码片段。

3.自定义对话框中使用了EditText,并且使用自定义键盘,同样需要通过构造函数将keyboardUtil对象传递,然后进行使用,并且可以通过

getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

来强制使用自定键盘。

因为我们项目的问题,需要插入IC读卡器,所有有些页面没法使用以上设置,不然则无法读取到IC的信息。

以上为我使用自定义键盘的一些总结,有些问题可能也不是很好,后期再进行完善。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值