Android 自定义数字键盘控件

因为项目中有个需求需要实现一个自定义键盘控件。起初通过layout使用组合控件的形式进行实现,后来看了感觉实在无法忍受于是就打算继承view然后通过绘制的方式进行实现。

git地址: https://gitee.com/zhengdd/MyWidget

具体思路如下

1  设置一些自定义属性如背景颜色,数字颜色,数字大小等,实现使用控件时候可自定义配置

2  通过获取控件宽高,计算控件中分割线,按钮等位置坐标。

3 通过背景颜色,线条,特殊单元格背景(如按下状态按钮背景),按键信息(数字或者图标)的顺序进行界面绘制。

4 重写onTouchEvent方法中,根据事件刷新界面并计算位置返回操作状态。

具体代码如下

public class NumKeyBoardView extends View {

    private float scale = 0;

    private int view_bg_color;

    private int line_color;

    private int btn_press_bg_color;

    private int btn_text_color;

    private ColorStateList csl_next_bg_color;

    private ColorStateList csl_next_text_color;

    private int next_bg_color;

    private int next_text_color;

    private static final int[] NEXT_STATE_ENABLE = {R.attr.next_enable};

    private static final int[] NEXT_STATE_DISABLE = {-R.attr.next_enable};

    private Drawable back_icon;

    private int text_size= 30;

    private boolean next_enable= true;

    private String next_text= "完成";

    private String[] numValues = new String[]{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",

            "delete", "next", "null", "null"};

    private Rect[] rects = new Rect[14];

    private float[] pts;

    private Rect pressedRect;

    private Bitmap mBpDelete;

    private float mBpWidth;

    private float mBpHeight;

    //控件宽度

    private int _witth;

    //控件高度

    private int _height;

    //单元格宽度

    private int _cell_width;

    //单元格高度

    private int _cell_height;

    private int linewidth = 1;

    private int textwidth = 1;

    private boolean isinitDate = false;

    public Paint mPaint;

    private int clickX = 0;

    private int clickY = 0;

    private String number = null;

    public boolean isPressed = false;

    private OnKeyBoardClickListener mListener;

    public NumKeyBoardView(Context context) {

        this(context, null);

    }

    public NumKeyBoardView(Context context, @Nullable AttributeSet attrs) {

        this(context, attrs, 0);

    }

    public NumKeyBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {

        super(context, attrs, defStyleAttr);

        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.NumKeyBoardView);

        next_enable = array.getBoolean(R.styleable.NumKeyBoardView_next_enable, true);

        csl_next_bg_color = array.getColorStateList(R.styleable.NumKeyBoardView_next_background);

        upNextEnable();

        init(array);

    }

    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        this._witth = MeasureSpec.getSize(widthMeasureSpec);

        this._height = MeasureSpec.getSize(heightMeasureSpec);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    }

    @Override

    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);

        if (!isinitDate) {

            initdata();

        }

        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        drawBackground(canvas);

        drawLine(canvas);

        drawCell(canvas);

        drawContent(canvas);

    }

    private void init(TypedArray typedArray) {

        if (typedArray != null) {

            view_bg_color = typedArray.getColor(R.styleable.NumKeyBoardView_view_background,

                    getResources().getColor(R.color.dong_color_white));

            line_color = typedArray.getColor(R.styleable.NumKeyBoardView_line_color,

                    getResources().getColor(R.color.dong_color_line_gray));

            btn_press_bg_color = typedArray.getColor(R.styleable.NumKeyBoardView_background_btn_press,

                    getResources().getColor(R.color.dong_color_btn_press_gray));

            btn_text_color = typedArray.getColor(R.styleable

                    .NumKeyBoardView_text_color_btn, getResources().getColor(R.color.dong_cokor_btn_text));

            back_icon = typedArray.getDrawable(R.styleable.NumKeyBoardView_icon_back);

            if (back_icon == null) {

                back_icon = getResources().getDrawable(R.drawable.dong_widget_icon_num_back);

            }

            next_text = typedArray.getString(R.styleable.NumKeyBoardView_text_next);

            if (TextUtils.isEmpty(next_text)) {

                next_text = "完成";

            }

            next_enable = typedArray.getBoolean(R.styleable.NumKeyBoardView_next_enable, true);

            text_size = typedArray.getDimensionPixelSize(R.styleable.NumKeyBoardView_text_size,

                    dip2px(20f));

            csl_next_bg_color = typedArray.getColorStateList(R.styleable.NumKeyBoardView_next_background);

            csl_next_text_color = typedArray.getColorStateList(R.styleable.NumKeyBoardView_text_next);

            upNextEnable();

        } else {

            view_bg_color = getResources().getColor(R.color.dong_color_white);

            line_color = getResources().getColor(R.color.dong_color_line_gray);

            btn_press_bg_color = getResources().getColor(R.color.dong_color_btn_press_gray);

            btn_text_color = getResources().getColor(R.color.dong_color_font_gray);

            if (next_enable) {

                next_bg_color = getResources().getColor(R.color.dong_color_next_bg_enable);

                next_text_color = getResources().getColor(R.color.dong_color_next_text_enable);

            } else {

                next_bg_color = getResources().getColor(R.color.dong_color_next_bg_disable);

                next_text_color = getResources().getColor(R.color.dong_color_next_text_disable);

            }

            back_icon = getResources().getDrawable(R.drawable.dong_widget_icon_num_back);

            upNextEnable();

        }

}

    private void initdata() {

        isinitDate = true;

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

        mPaint.setStrokeWidth(linewidth);

        _cell_width = _witth / 4;

        _cell_height = _height / 4;

        mBpDelete = ((BitmapDrawable) back_icon).getBitmap();

        mBpWidth = mBpDelete.getWidth();

        mBpHeight = mBpDelete.getHeight();

        //10条分割线数组

        pts = new float[]{

                0, 0, _witth, 0,

                0, _cell_height, _cell_width * 3, _cell_height,

                0, _cell_height * 2, _witth, _cell_height * 2,

                0, _cell_height * 3, _cell_width * 3, _cell_height * 3,

                0, _height, _witth, _height,

                0, 0, 0, _height,

                _cell_width, 0, _cell_width, _height,

                _cell_width * 2, 0, _cell_width * 2, _height,

                _cell_width * 3, 0, _cell_width * 3, _height,

                _witth, 0, _witth, _height

        };

        rects[0] = new Rect(_cell_width, _cell_height * 3, _cell_width * 2, _height);

        rects[1] = new Rect(0, 0, _cell_width, _cell_height);

        rects[2] = new Rect(_cell_width, 0, _cell_width * 2, _cell_height);

        rects[3] = new Rect(_cell_width * 2, 0, _cell_width * 3, _cell_height);

        rects[4] = new Rect(0, _cell_height, _cell_width, _cell_height * 2);

        rects[5] = new Rect(_cell_width, _cell_height, _cell_width * 2, _cell_height * 2);

        rects[6] = new Rect(_cell_width * 2, _cell_height, _cell_width * 3, _cell_height * 2);

        rects[7] = new Rect(0, _cell_height * 2, _cell_width, _cell_height * 3);

        rects[8] = new Rect(_cell_width, _cell_height * 2, _cell_width * 2, _cell_height * 3);

        rects[9] = new Rect(_cell_width * 2, _cell_height * 2, _cell_width * 3, _cell_height * 3);

        rects[10] = new Rect(_cell_width * 3, 0, _witth, _cell_height * 2);

        rects[11] = new Rect(_cell_width * 3, _cell_height * 2, _witth, _height);

        //默认空按钮位置

        rects[12] = new Rect(0, _cell_height * 3, _cell_width, _height);

        rects[13] = new Rect(_cell_width * 2, _cell_height * 3, _cell_width * 3, _height);

    }

    /**

* 绘制底色

*

    * @param canvas

    */

    private void drawBackground(Canvas canvas) {

        canvas.drawColor(view_bg_color);

    }

    /**

* 绘制线条

*

    * @param canvas

    */

    private void drawLine(Canvas canvas) {

        mPaint.setColor(line_color);

        mPaint.setStrokeWidth(linewidth);

        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        canvas.drawLines(pts, mPaint);

    }

    /**

* 绘制点击的按钮颜色 和 下一步按钮背景色

*

    * @param canvas

    */

    private void drawCell(Canvas canvas) {

        if (isPressed && pressedRect != null) {

            mPaint.setColor(btn_press_bg_color);

            mPaint.setStrokeWidth(linewidth);

            mPaint.setStyle(Paint.Style.FILL);

            canvas.drawRect(pressedRect, mPaint);

        }

        mPaint.setColor(next_bg_color);

        mPaint.setStrokeWidth(linewidth);

        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        canvas.drawRect(rects[11], mPaint);

    }

    /**

* 绘制文字及icon颜色

*

    * @param canvas

    */

    private void drawContent(Canvas canvas) {

        mPaint.setColor(btn_text_color);

        mPaint.setStrokeWidth(textwidth);

        mPaint.setTextSize(text_size);

        mPaint.setTextAlign(Paint.Align.CENTER);

        for (int i = 0; i < 10; i++) {

            drawTextCenter(rects[i], mPaint, numValues[i], canvas);

        }

        mPaint.setColor(next_text_color);

        mPaint.setStrokeWidth(textwidth);

        mPaint.setTextSize(text_size);

        mPaint.setTextAlign(Paint.Align.CENTER);

        drawTextCenter(rects[11], mPaint, next_text, canvas);

        drawBitmapCenter(rects[10], mPaint, mBpDelete, canvas);

    }

    private void drawBitmapCenter(Rect rect, Paint paint, Bitmap bitmap, Canvas canvas) {

        float x = rect.centerX() - (mBpWidth / 2);

        float y = rect.centerY() - (mBpHeight / 2);

        canvas.drawBitmap(bitmap, x, y, paint);

    }

    private void drawTextCenter(Rect rect, Paint textPaint, String text, Canvas canvas) {

        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();

        float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top

        float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom

        int baseLineY = (int) (rect.centerY() - top / 2 - bottom / 2);//基线中间点的y轴计算公式

        canvas.drawText(text, rect.centerX(), baseLineY, textPaint);

    }

    /**

* 设置下一步操作控制名称

*

    * @param nexttext

    */

    public void setNextText(String nexttext) {

        if (!TextUtils.isEmpty(nexttext)) {

            this.next_text = nexttext;

            invalidate();

        }

}

    public void setNextEnable(boolean enable) {

        if (next_enable != enable) {

            next_enable = enable;

            refreshDrawableState();

            upNextEnable();

            invalidate();

        }

}

    private void upNextEnable() {

        if (csl_next_bg_color != null) {

            next_bg_color = csl_next_bg_color.getColorForState(getDrawableState(), 0);

        } else {

            if (next_enable) {

                next_bg_color = getResources().getColor(R.color.dong_color_next_bg_enable);

            } else {

                next_bg_color = getResources().getColor(R.color.dong_color_next_bg_disable);

            }

}

        if (csl_next_text_color != null) {

            next_text_color = csl_next_text_color.getColorForState(getDrawableState(), 0);

        } else {

            if (next_enable) {

                next_text_color = getResources().getColor(R.color.dong_color_next_text_enable);

            } else {

                next_text_color = getResources().getColor(R.color.dong_color_next_text_disable);

            }

}

}

    public void setOnKeyBoardClickListener(@Nullable OnKeyBoardClickListener l) {

        if (l != null) {

            mListener = l;

        }

}

    private int dip2px(float dpValue) {

        /*当前view的缩放比例*/

        if (0 == scale) {

            scale = this.getContext().getResources().getDisplayMetrics().density;

        }

        return (int) (dpValue * scale + 0.5f);

    }

    public interface OnKeyBoardClickListener {

        void onOutPut(String num);

        void onDetele();

        void onNextClick();

    }

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        clickX = (int) event.getX();

        clickY = (int) event.getY();

        switch (event.getAction()) {

            case MotionEvent.ACTION_DOWN: //按下

                isPressed = true;

                handleDown();

                invalidate();

                return true;

            case MotionEvent.ACTION_UP: //弹起

                if (mListener != null) {

                    switch (number) {

                        case "null":

                            break;

                        case "delete":

                            mListener.onDetele();

                            break;

                        case "next":

                            if (next_enable) {

                                mListener.onNextClick();

                            }

                            break;

                        default:

                            mListener.onOutPut(number);

                            break;

                    }

}

                setDefault();

                invalidate();

                return true;

            case MotionEvent.ACTION_CANCEL:  //取消

//恢复默认值

                setDefault();

                return true;

            default:

                break;

        }

        return false;

    }

    private void handleDown() {

        for (int i = 0; i < numValues.length; i++) {

            if (rects[i].contains(clickX, clickY)) {

                number = numValues[i];

                pressedRect = rects[i];

                switch (number) {

                    case "null":

                    case "delete":

                    case "next":

                        pressedRect = null;

                        break;

                    default:

                        break;

                }

                return;

            }

}

}

    private void setDefault() {

        clickX = 0;

        clickY = 0;

        number = null;

        pressedRect = null;

        isPressed = false;

    }

    @Override

    protected int[] onCreateDrawableState(int extraSpace) {

        int drawableState[] = super.onCreateDrawableState(extraSpace + 1);

        if (next_enable) {

            mergeDrawableStates(drawableState, NEXT_STATE_ENABLE);

        } else {

            mergeDrawableStates(drawableState, NEXT_STATE_DISABLE);

        }

        return drawableState;

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容