Dialog上的EditText的自定义键盘

公司出了新的需求,对话框上有三个输入框,有一个输入框调用系统键盘,有两个输入框调用自定义键盘。
思路:自定义Edittext,获取焦点时,弹出一个popuwindow。但是因为是在Dialog上,所以如果确定当前的页面是最麻烦的。下面是代码:

package cn.startinfo.dingdao.view;

public class KeyboardEditText extends EditText implements KeyboardView.OnKeyboardActionListener {

    private Keyboard mKeyboard;
    private KeyboardView mKeyboardView;

    private Window mWindow;
    private View mDecorView;
    private View mContentView;

    private PopupWindow mKeyboardWindow;

    private boolean isNeedCustomKeyboard = true; // 是否启用自定义键盘
    /**
     * 输入框在被键盘弹出时,要被推上的距离
     */
    private int mScrollDistance = 0;

    public static int screenWidth = -1; // 未知宽高
    public static int screenHeight = -1;

    /**
     * 不包含导航栏的高度
     */
    public static int screenHeightNoNavBar = -1;
    /**
     * 实际内容高度,  计算公式:屏幕高度-导航栏高度-电量栏高度
     */
    public static int screenContentHeight = -1;
    public static float density = 1.0f;
    public static int densityDpi = 160;

    public KeyboardEditText(Context context) {
        this(context, null);
    }

    public KeyboardEditText(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public KeyboardEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttributes(context);
        initKeyboard(context, attrs);
    }

    private void initKeyboard(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.Keyboard);
        if (array.hasValue(R.styleable.Keyboard_xml)) {
            isNeedCustomKeyboard = true;
            int xmlId = array.getResourceId(R.styleable.Keyboard_xml, 0);
            mKeyboard = new Keyboard(context, xmlId);

            mKeyboardView = (KeyboardView) LayoutInflater.from(context).inflate(R.layout.my_keyboard_view, null);

            mKeyboardView.setKeyboard(mKeyboard);
            mKeyboardView.setEnabled(true);
            mKeyboardView.setPreviewEnabled(false);
            mKeyboardView.setOnKeyboardActionListener(this);

            mKeyboardWindow = new PopupWindow(mKeyboardView,
                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
                    //showAtLocation这里去获取当前的页面
                    //如果是普通activity的页面
                    //mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0);甚至不需要这行代码
                    //原因
            mKeyboardWindow.showAtLocation(((Activity)((ContextWrapper)getContext()).getBaseContext()).getWindow().getDecorView(),Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL,0,0);

            mKeyboardWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
                @Override
                public void onDismiss() {
                    if (mScrollDistance > 0) {
                        int temp = mScrollDistance;
                        mScrollDistance = 0;
                        if (null != mContentView) {
                            mContentView.scrollBy(0, -temp);
                        }
                    }
                }
            });
        } else {
            isNeedCustomKeyboard = false;
        }

        array.recycle();
    }

    private void initAttributes(Context context) {
        initScreenParams(context);
        this.setLongClickable(false); // 设置EditText不可长按
        this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
        removeCopyAbility();

        if (this.getText() != null) {
            this.setSelection(this.getText().length());
        }

        this.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    hideKeyboard();
                }
            }
        });
    }

    @TargetApi(11)
    private void removeCopyAbility() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            this.setCustomSelectionActionModeCallback(new ActionMode.Callback() {
                @Override
                public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                    return false;
                }

                @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) {

                }
            });
        }
    }

    private void initScreenParams(Context context) {
        DisplayMetrics metrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        display.getMetrics(metrics);

        screenWidth = metrics.widthPixels;
        screenHeight = metrics.heightPixels;
        density = metrics.density;
        densityDpi = metrics.densityDpi;

        screenHeightNoNavBar = screenHeight;

        int version = Build.VERSION.SDK_INT;
        // 新版本的android 系统有导航栏,造成无法正确获取高度
        if (version == 13) {
            try {
                Method method = display.getClass().getMethod("getRealHeight");
                screenHeightNoNavBar = (Integer) method.invoke(display);
            } catch (Exception e) {
                // do nothing
            }
        } else if (version > 13) {
            try {
                Method method = display.getClass().getMethod("getRawHeight");
                screenHeightNoNavBar = (Integer) method.invoke(display);
            } catch (Exception e) {
                // do nothing
            }
        }

        screenContentHeight = screenHeightNoNavBar - getStatusBarHeight(context);
    }

    /**
     * 获取状态栏高度
     */
    private int getStatusBarHeight(Context context) {
        Class<?> clazz = null;
        Object object = null;
        Field field = null;
        int x = 0;
        int statusBarHeight = 0;
        try {
            clazz = Class.forName("com.android.internal.R$dimen");
            object = clazz.newInstance();
            field = clazz.getField("status_bar_height");
            x = Integer.parseInt(field.get(object).toString());
            statusBarHeight = context.getResources().getDimensionPixelSize(x);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return statusBarHeight;
    }


    @Override
    public void onPress(int primaryCode) {

    }

    @Override
    public void onRelease(int primaryCode) {

    }

    @Override
    public void onKey(int primaryCode, int[] keyCodes) {
        Editable editable = this.getText();
        int start = this.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(0x0<=primaryCode&& primaryCode<=0x7f){
            editable.insert(start, Character.toString((char) primaryCode));
        }
        //ASCII为0-127,若要自定义获取keylabel的值,则需要超过127
        //附上ASCII表链接http://www.asciima.com/
        else if(primaryCode >0x7f){
            Keyboard.Key key = getKeyByKeyCode(primaryCode);
            editable.insert(start, key.label);
        }else{
        }
    }

    private Keyboard.Key getKeyByKeyCode(int primaryCode) {
        if(null != mKeyboard){
            List<Key> keyList = mKeyboard.getKeys();
            for (int i =0,size= keyList.size(); i < size; i++) {
                Key key = keyList.get(i);

                int codes[] = key.codes;

                if(codes[0] == primaryCode){
                    return key;
                }
            }
        }

        return null;
    }

    @Override
    public void onText(CharSequence text) {

    }

    @Override
    public void swipeLeft() {

    }

    @Override
    public void swipeRight() {

    }

    @Override
    public void swipeDown() {

    }

    @Override
    public void swipeUp() {

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        requestFocus();
        requestFocusFromTouch();

        if (isNeedCustomKeyboard) {
            hideSysInput();
            showKeyboard();
        }


        return true;
    }

    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);

    }

    public void onAttachedToWindow(){
        super.onAttachedToWindow();
        //如果是普通的activity页面
        //则代码为this.mWindow = ((Activity)getContext()).getWindow();
        //具体原因参见http://www.imooc.com/article/7831
        this.mWindow = ((Activity)((ContextWrapper)getContext()).getBaseContext()).getWindow();
        this.mDecorView =this.mWindow .getDecorView();
        this.mContentView =this.mWindow.findViewById(Window.ID_ANDROID_CONTENT);

        hideSysInput();
    }

    public void onDetachedFromWindow(){
        super.onDetachedFromWindow();

        hideKeyboard();

        mKeyboardWindow = null;
        mKeyboardView = null;
        mKeyboard = null;

        mDecorView = null;
        mContentView = null;
        mWindow = null;
    }

    private void showKeyboard() {
        if (null != mKeyboardWindow) {
            if (!mKeyboardWindow.isShowing()) {

                mKeyboardView.setKeyboard(mKeyboard);
                mKeyboardWindow.showAtLocation(this.mDecorView, Gravity.BOTTOM, 0, 0);
//                mKeyboardWindow.update();

                if (null != mDecorView && null != mContentView) {
                    int[] pos = new int[2];
                    getLocationOnScreen(pos);
                    float height = dpToPx(getContext(), 240);

                    int[] hsmlpos = new int[2];
                    mDecorView.getLocationOnScreen(hsmlpos);

                    Rect outRect = new Rect();
                    mDecorView.getWindowVisibleDisplayFrame(outRect);

                    int screen = screenContentHeight;
                    mScrollDistance = (int) ((pos[1] + getMeasuredHeight() - outRect.top) - (screen - height));

                    if (mScrollDistance > 0) {
                        mContentView.scrollBy(0,mScrollDistance);
                    }
                }
            }
        }
    }

    public void hideKeyboard() {
        if (null != mKeyboardWindow) {
            if (mKeyboardWindow.isShowing()) {
                mKeyboardWindow.dismiss();
            }
        }
    }

    /**
     * 密度转换为像素值
     */
    private float dpToPx(Context context, int dp) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    private void hideSysInput() {
        if (this.getWindowToken() != null) {
            InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(this.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }



    class KeyModel {
        private Integer code;
        private String label;

        public KeyModel(Integer code, String label) {
            this.code = code;
            this.label = label;
        }

        public String getLabel() {
            return label;
        }

        public void setLabel(String label) {
            this.label = label;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        @Override
        public String toString() {
            return "code:"+code+","+"label:"+label;
        }
    }
}

xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<!-- 可以直接输入的字符(如0-9,.),他们在键盘映射xml中的android:codes值必须配置为该字符的ASCII码 -->
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"

    android:keyWidth="25%p" android:horizontalGap="1px"
    android:verticalGap="1px" 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="43" android:keyLabel="+"/>
    </Row>
    <Row>
        <Key android:codes="52" android:keyLabel="4" />
        <Key android:codes="53" android:keyLabel="5" />
        <Key android:codes="54" android:keyLabel="6" />
        <Key android:codes="45" android:keyLabel="-"/>
    </Row>
    <Row>
        <Key android:codes="55" android:keyLabel="7" />
        <Key android:codes="56" android:keyLabel="8" />
        <Key android:codes="57" android:keyLabel="9" />
        <Key android:codes="-5" android:keyLabel="删除" android:keyIcon="@color/red"  />

    </Row>
    <Row>
        <Key android:codes="128"
            android:keyLabel="宽"
            />
        <!--<Key android:codes="484848" android:keyLabel="000"-->
        <!--android:keyWidth="34%p"/>-->
        <Key android:codes="48" android:keyLabel="0"/>
        <Key android:codes="129" android:keyLabel="高"
            />
        <Key android:codes="-3" android:keyLabel="隐藏"/>
    </Row>
</Keyboard>
public class MyKeyboardView extends KeyboardView {

    private Drawable mKeyBgDrawable;
    private Drawable mOpKeyBgDrawable;
    private Resources mRes;

    public MyKeyboardView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyKeyboardView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initResources(context);
    }

    private void initResources(Context context) {
        mRes = context.getResources();
        mKeyBgDrawable = mRes.getDrawable(R.drawable.btn_keyboard_key);
        mOpKeyBgDrawable = mRes.getDrawable(R.drawable.btn_keyboard_opkey);
    }

    @Override
    public void onDraw(Canvas canvas) {
        List<Keyboard.Key> keys = getKeyboard().getKeys();
        for (Keyboard.Key key : keys) {
            canvas.save();

            int offsetY = 0;
            if (key.y == 0) {
                offsetY = 1;
            }
            int initDrawY = key.y + offsetY;
            Rect rect = new Rect(key.x, initDrawY, key.x + key.width, key.y + key.height);
            canvas.clipRect(rect);

            int primaryCode = -1;
            if (null != key.codes && key.codes.length != 0) {
                primaryCode = key.codes[0];
            }

            Drawable drawable = null;
            if (primaryCode == -3 || key.codes[0] == -5) {
                drawable = mOpKeyBgDrawable;
            } else if (primaryCode != -1) {
                drawable = mKeyBgDrawable;
            }

            if (null != drawable) {
                int[] state = key.getCurrentDrawableState();
                drawable.setState(state);
                drawable.setBounds(rect);
                drawable.draw(canvas);
            }

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setTextAlign(Paint.Align.CENTER);
            paint.setTextSize(50);
            paint.setStrokeWidth(2);
            paint.setColor(mRes.getColor(R.color.black));

            if (key.label != null) {
                canvas.drawText(
                        key.label.toString(),
                        key.x + (key.width / 2),
                        initDrawY + (key.height + paint.getTextSize() - paint.descent()) / 2,
                        paint
                );
            } else if (key.icon != null) {
                int intriWidth = key.icon.getIntrinsicWidth();
                int intriHeight = key.icon.getIntrinsicHeight();

                final int drawableX = key.x + (key.width - intriWidth) / 2;
                final int drawableY = initDrawY + (key.height - intriHeight) / 2;

                key.icon.setBounds(drawableX, drawableY,
                        drawableX + intriWidth, drawableY + intriHeight);
                key.icon.draw(canvas);
            }

            canvas.restore();
        }
    }

}

最后自定义键盘和系统键盘的切换

//调用系统键盘
mEdiMingcheng.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                mEditDongkou.hideKeyboard();
                dialog.getWindow()
                        .clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
            }
        });

//调用自定义键盘
        mEditDongkou.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                dialog.getWindow()
                        .setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);

            }
        });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值