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

    private int nCurKeyboardKeyNums;//当前键盘的按键数量
    private Keyboard nCurrentKeyboard;
    private List 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




    

        

        

        

        

        

        

        

        
        

        
    

    
        

        

        

        

        

        

        

        

        
    

    
        

        

        

        

        

        

        

        

        

    

    

        

        

        

        

        
    

symbols.xml




    
        
        

        
        

        
        
        
        
        
        
    

    
        
        
        
        
        
        
        
        
        
        
    
    
        
        
        
        
        
        
        
        
        
        
    
    
        

        

        
        

        
        

        
    

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

二、如何使用

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



        

        
    

其中:

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的信息。

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

你可能感兴趣的:(android)