天天看点

自定义数字键盘类似于系统键盘

最近因为项目需求要自定义一个数字键盘,在网上查了些资料但很多功能不全,很多场景不能适应。今天就结合网上的一些资料打算自己写一个键盘。主要适应二种场景:

1、支付密码 需要随机键盘

2、点击EditText能自动向上顶布局

源码下载地址:http://git.oschina.net/shikh/CustomView-master

先看一下使用方法:

<expand.shikh.com.customview.keyboard.NumberKeyBoardEditText
        android:layout_alignParentBottom="true"
        android:id="@+id/etChar"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:layout_marginTop="10dp"
        android:background="#ace"
        android:gravity="center"
        android:hint="数字键盘"
        android:singleLine="true"
        android:textColor="#ffffff"
        android:textColorHint="#ffffff"
        mykeyboard:xml="@xml/symbols"
        mykeyboard:randomkeys="true"
        />
           

只需引用我们自定义的editText 控件就欧了~

先看一下效果图

自定义数字键盘类似于系统键盘

下面来说说我们的实现方式:

实现软键盘主要用到了系统的两个类Keyboard和KeyboardView:

Keyboard类源码的介绍是: Listener for virtual keyboard events.即用于监听虚拟键盘。至于Keyboard类的映射机制,这里就不需要说了,要分析源码请移驾http://blog.csdn.net/pi9nc/article/details/27304459

1、在res文件下,新建一个xml文件,下面放数字键盘的布局文件

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:horizontalGap="1dp"
    android:keyWidth="33.33333%p"
    android:verticalGap="1dp">
    <Row android:keyHeight="7%p">
        <Key android:codes="-3" android:keyIcon="@mipmap/keyboard_back_img" android:keyWidth="100%p" />
    </Row>
    <Row  android:keyHeight="10%p">
        <Key android:codes="55" android:keyLabel="7" />
        <Key android:codes="56" android:keyLabel="8" />
        <Key android:codes="57" android:keyEdgeFlags="right" android:keyLabel="9" />
    </Row>
    <Row  android:keyHeight="10%p">
        <Key android:codes="52" android:keyLabel="4" />
        <Key android:codes="53" android:keyLabel="5" />
        <Key android:codes="54" android:keyEdgeFlags="right" android:keyLabel="6" />

    </Row>
    <Row  android:keyHeight="10%p">
        <Key android:codes="49" android:keyLabel="1" />
        <Key android:codes="50" android:keyLabel="2" />
        <Key android:codes="51" android:keyEdgeFlags="right" android:keyLabel="3" />
    </Row>
    <Row  android:keyHeight="10%p">
        <Key android:codes="4896" android:keyLabel="清空" />
        <!--<Key
            android:codes="46"
            android:keyLabel="." />-->
        <Key android:codes="48" android:keyLabel="0" />
        <!--<Key android:codes="-3" android:keyEdgeFlags="right" android:keyLabel="OK"/>-->
        <!--<key android:codes="4896" android:keylabel="清空" />-->
        <Key android:codes="-5" android:keyEdgeFlags="right" android:keyIcon="@mipmap/keyboard_delete_img" />
    </Row>
</Keyboard>
           

3、创建键盘的工具类KeyboardUtil(显示键盘的主要代码),如下:

public class KeyboardUtil {
    private KeyboardView keyboardView;
    private Keyboard k;// 数字键盘
    private EditText ed;
    private Context mContext;
    private PopupWindow mKeyboardWindow;

    public Keyboard getK() {
        return k;
    }

    public KeyboardView getKeyboardView() {
        return keyboardView;
    }

    public void setmKeyboardWindow(PopupWindow mKeyboardWindow) {
        this.mKeyboardWindow = mKeyboardWindow;
    }

    /**
     * 键盘置于布局文件中
     * @author shikh
     * @time 2016/12/8 上午10:19
     */
    public KeyboardUtil(Activity atx, EditText edit,int keyId,int xmlId){
        this.ed = edit;
        this.mContext = atx;
        k = new Keyboard(atx, xmlId == ?R.xml.symbols:xmlId);
        keyboardView = (KeyboardView) atx.findViewById(keyId);
        initKeyBoard();
    }

    /**
     * 键盘用popwindow 形式打开 结合 numberKeyBoardEditText 使用 具有向上顶布局的功能
     * @author shikh
     * @time 2016/12/8 上午10:22
     */
    public KeyboardUtil(Context ctx, EditText edit, int xmlId) {
        this.ed = edit;
        this.mContext = ctx;
        k = new Keyboard(ctx, xmlId == ?R.xml.symbols:xmlId);
        keyboardView = (KeyboardView) View.inflate(ctx,R.layout.layout_keyboard_view,null);
    }


    public void initKeyBoard(){
        keyboardView.setKeyboard(k);
        keyboardView.setEnabled(true);
        keyboardView.setPreviewEnabled(false);
        keyboardView.setVisibility(View.VISIBLE);
        keyboardView.setOnKeyboardActionListener(listener);
    }
    private KeyboardView.OnKeyboardActionListener listener = new KeyboardView.OnKeyboardActionListener() {
        @Override
        public void swipeUp() {}

        @Override
        public void swipeRight() {}

        @Override
        public void swipeLeft() {}

        @Override
        public void swipeDown() {}

        @Override
        public void onText(CharSequence text) {}

        @Override
        public void onRelease(int primaryCode) {}

        @Override
        public void onPress(int primaryCode) {}

        //一些特殊操作按键的codes是固定的比如完成、回退等
        @Override
        public void onKey(int primaryCode, int[] keyCodes) {
            Editable editable = ed.getText();
            int start = ed.getSelectionStart();
            if (primaryCode == Keyboard.KEYCODE_DELETE) {// 回退
                if (editable != null && editable.length() > ) {
                    if (start > ) {
                        editable.delete(start - , start);
                    }
                }
            } else if (primaryCode == ) {// 清空
                editable.clear();
            } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {//
                hideKeyboard();
            } else if (primaryCode == ) { // 小数点
                String text = ed.getText().toString();
                if (!text.contains(".") && text.length() >) {
                    editable.insert(start, Character.toString((char) primaryCode));
                }
            } else { //将要输入的数字现在编辑框中
                editable.insert(start, Character.toString((char) primaryCode));
            }
        }
    };



    /**
     * 实应于 键盘布局放置在activity 布局文件中
     * @author shikh
     * @time 2016/12/8 上午10:08
     */
    public boolean isShow() {
        int visibility = keyboardView.getVisibility();
        if (visibility == View.VISIBLE) {
            return true;
        }
        return false;
    }
    public void showKeyboard() {
        int visibility = keyboardView.getVisibility();
        if (visibility == View.GONE || visibility == View.INVISIBLE) {
            keyboardView.setVisibility(View.VISIBLE);
        }
    }

    public void hideKeyboard() {
        if (null != mKeyboardWindow) {
            if (mKeyboardWindow.isShowing()) {
                mKeyboardWindow.dismiss();
            }
        }else {
            int visibility = keyboardView.getVisibility();
            if (visibility == View.VISIBLE) {
                keyboardView.setVisibility(View.GONE);
            }
        }

    }
    /**
     * 隐藏系统键盘
     * @author shikh
     * @time 2016/12/8 下午3:19
     */
    public void hideSoftInputMethod(Window mWindow) {
        mWindow.setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        int currentVersion = android.os.Build.VERSION.SDK_INT;
        String methodName = null;
        if (currentVersion >= ) {
            // 4.2
            methodName = "setShowSoftInputOnFocus";
        } else if (currentVersion >= ) {
            // 4.0
            methodName = "setSoftInputShownOnFocus";
        }
        if (methodName == null) {
            ed.setInputType(InputType.TYPE_NULL);
        } else {
            Class<EditText> cls = EditText.class;
            Method setShowSoftInputOnFocus;
            try {
                setShowSoftInputOnFocus = cls.getMethod(methodName,
                        boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(ed, false);
            } catch (NoSuchMethodException e) {
                ed.setInputType(InputType.TYPE_NULL);
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
           

4、自定义EditText 控件NumberKeyBoardEditText ,实现触摸弹出自定义键盘,先要创建一个 KeyBoardView 布局供 popupWindow使用

<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/keyboard_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:background="#dddddd"
    android:focusable="true"
    android:focusableInTouchMode="true"
    android:keyBackground="@drawable/bg_keyboard_btn"
    android:keyTextColor="@color/keyTextColor"
    android:keyTextSize="24sp"
    android:paddingTop="1dp"
    android:shadowRadius="0.0"
    android:visibility="gone" />
           

NumberKeyBoardEditText 类的主要代码

public NumberKeyBoardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttributes(context);
        initKeyBoard(context, attrs);
        initPopWindow();
    }

    private void initKeyBoard(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.keyboard);
        if (a.hasValue(R.styleable.keyboard_xml)) {
            needcustomkeyboard = true;
            int xmlid = a.getResourceId(R.styleable.keyboard_xml, );
            keyboardUtil = new KeyboardUtil(context, this, xmlid);
        } else {
            keyboardUtil = new KeyboardUtil(context, this, );
        }
        if (a.hasValue(R.styleable.keyboard_randomkeys)) {
            randomkeys = a.getBoolean(R.styleable.keyboard_randomkeys, false);
        }

        mKeyboardView = keyboardUtil.getKeyboardView();
        mKeyboard = keyboardUtil.getK();
        if (randomkeys) {//随机键盘
            randomdigkey(mKeyboard);
        }
        keyboardUtil.initKeyBoard();
        a.recycle();
    }

    private void initPopWindow() {
        mKeyboardWindow = new PopupWindow(keyboardUtil.getKeyboardView(), ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        mKeyboardWindow.setAnimationStyle(R.style.AnimationFade);//设置动画效果,文件在资源里面,这里就不贴出来。</span></strong>
        // mKeyboardWindow.setBackgroundDrawable(new BitmapDrawable());
        // mKeyboardWindow.setOutsideTouchable(true);
        keyboardUtil.setmKeyboardWindow(mKeyboardWindow);
        mKeyboardWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {

            @Override
            public void onDismiss() {
                // TODO Auto-generated method stub
                if (scrolldis > ) {
                    int temp = scrolldis;
                    scrolldis = ;
                    if (null != mContentView) {
                        //使布局整体向上顶的关键代码,使用布局的scrollBy重新滚动位置
                        mContentView.scrollBy(, -temp);
                    }
                }
            }
        });

    }
           
// 暂时未使用到,为了实现随机键盘布局
    private void randomdigkey(Keyboard mKeyboard) {
        if (mKeyboard == null) {
            return;
        }
        List<Keyboard.Key> keyList = mKeyboard.getKeys();
        // 查找出0-9的数字键
        List<Keyboard.Key> newkeyList = new ArrayList<Keyboard.Key>();
        for (int i = , size = keyList.size(); i < size; i++) {
            Keyboard.Key key = keyList.get(i);
            CharSequence label = key.label;
            if (label != null && isNumber(label.toString())) {
                newkeyList.add(key);
            }
        }

        int count = newkeyList.size();
        List<KeyModel> resultList = new ArrayList<KeyModel>();
        LinkedList<KeyModel> temp = new LinkedList<KeyModel>();

        for (int i = ; i < count; i++) {
            temp.add(new KeyModel( + i, i + ""));
        }
        Random rand = new SecureRandom();
        rand.setSeed(SystemClock.currentThreadTimeMillis());

        for (int i = ; i < count; i++) {
            int num = rand.nextInt(count - i);
            KeyModel model = temp.get(num);
            resultList.add(new KeyModel(model.getCode(), model.getLable()));
            temp.remove(num);
        }

        for (int i = , size = newkeyList.size(); i < size; i++) {
            Keyboard.Key newKey = newkeyList.get(i);
            KeyModel resultmodle = resultList.get(i);
            newKey.label = resultmodle.getLable();
            newKey.codes[] = resultmodle.getCode();
        }

    }
           
@Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        requestFocus();
        requestFocusFromTouch();
//        if (needcustomkeyboard) {
            hideSysInput();
            showKeyboard();
//        }
        return true;
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (null != mKeyboardWindow) {
                if (mKeyboardWindow.isShowing()) {
                    mKeyboardWindow.dismiss();
                    return true;
                }
            }
        }
        return super.onKeyDown(keyCode, event);
    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        this.mWindow = ((Activity) getContext()).getWindow();
        this.mDecorView = this.mWindow.getDecorView();
        this.mContentView = this.mWindow.findViewById(Window.ID_ANDROID_CONTENT);
//        hideSysInput();
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        hideKeyboard();
        mKeyboardWindow = null;
        mKeyboardView = null;
        mKeyboard = null;
        mDecorView = null;
        mContentView = null;
        mWindow = null;
    }