android自定義view(自定義數字鍵盤)

序言:在上週的項目中,須要作一個密碼鎖的功能,而後密碼下面還得有鍵盤,就相似支付寶支付的時候那樣:

固然了,咱們項目的需求簡單點,純數字的就能夠了,而後上週就百度了自定義鍵盤,隨便找了一個修改修改就用到項目中去了。

多謝這位簡友:[Android] 自定義輸入支付密碼的軟鍵盤git

今天本身抽空寫了一個自定義View的鍵盤控件,下面跟你們分享一下:

####思路: 一、佈局:github

(1)、宮格:咱們能夠將這個佈局當作是宮格佈局,而後須要計算出每一個小宮格在屏幕中的位置(座標),而後再用canvas畫出相應的矩形便可。
(2)、數字:咱們須要計算出每一個小宮格中的中心點位置(座標),而後用canvas畫數字上去,固然,咱們知道最後一個是刪除鍵,並非數字,咱們能夠準備一張圖片,將圖片畫到相應的位置。
複製代碼

二、用戶動做:canvas

(1)、按下:用戶每一次按下的時候就表示這一次動做的開始,因此首先要將各類標識位(自定義所須要的標識位)設置成初始狀態,而後須要記錄按下的座標,而後計算出用戶按下的座標與宮格中哪一個點相對應,在記錄相應數字。最後刷新佈局
(2)、擡起:用戶擡起的時候須要刷新佈局,而後將按下過程當中記錄下的數字或者刪除鍵信息經過接口的形式回調給用戶,最後恢復標識位
(3)、取消:將全部的標識位恢復成初始狀態。
複製代碼

好了,思路就講到這裏,咱們來看看onDraw方法:佈局

protected void onDraw(Canvas canvas) {
	if (!isInit) {
        initData();
   }
   mPaint.setColor(Color.WHITE);
    //畫宮格
    //第一排
    canvas.drawRoundRect(10, mHeight / 2 + 10, 10 + mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 10, 20 + 2 * mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 10, 30 + 3 * mRectWidth, mHeight / 2 + 10 + mRectHeight, 10, 10, mPaint);
    //第二排
    canvas.drawRoundRect(10, mHeight / 2 + 20 + mRectHeight, 10 + mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 20 + mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 20 + mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 20 + 2 * mRectHeight, 10, 10, mPaint);
    //第三排
    canvas.drawRoundRect(10, mHeight / 2 + 30 + 2 * mRectHeight, 10 + mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 30 + 2 * mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);
    canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 30 + 2 * mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 30 + 3 * mRectHeight, 10, 10, mPaint);
    //第四排
    mPaint.setColor(Color.GRAY);
    canvas.drawRoundRect(10, mHeight / 2 + 40 + 3 * mRectHeight, 10 + mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);
    mPaint.setColor(Color.WHITE);
    canvas.drawRoundRect(20 + mRectWidth, mHeight / 2 + 40 + 3 * mRectHeight, 20 + 2 * mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);
    mPaint.setColor(Color.GRAY);
    canvas.drawRoundRect(30 + 2 * mRectWidth, mHeight / 2 + 40 + 3 * mRectHeight, 30 + 3 * mRectWidth, mHeight / 2 + 40 + 4 * mRectHeight, 10, 10, mPaint);


    mPaint.setColor(Color.BLACK);
    mPaint.setTextSize(60);// 設置字體大小
    mPaint.setStrokeWidth(2);
    //畫數字
    //第一排
    canvas.drawText("1", xs[0], ys[0], mPaint);
    canvas.drawText("2", xs[1], ys[0], mPaint);
    canvas.drawText("3", xs[2], ys[0], mPaint);
    //第二排
    canvas.drawText("4", xs[0], ys[1], mPaint);
    canvas.drawText("5", xs[1], ys[1], mPaint);
    canvas.drawText("6", xs[2], ys[1], mPaint);
    //第三排
    canvas.drawText("7", xs[0], ys[2], mPaint);
    canvas.drawText("8", xs[1], ys[2], mPaint);
    canvas.drawText("9", xs[2], ys[2], mPaint);
    //第四排
    canvas.drawText(".", xs[0], ys[3], mPaint);
    canvas.drawText("0", xs[1], ys[3], mPaint);
    canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);
}
複製代碼
注:上面的座標須要咱們本身算出,耐心一點,很容易算的,你只須要搞清楚在Android中屏幕是怎樣的座標系就能夠了。座標算出來以後,咱們先畫宮格,而後再畫數字和刪除鍵,這裏有人要問了,我能夠先畫數字嗎,NO,由於當你畫完數字以後再畫宮格你會發現數字不見了,爲何呢?**被你的宮格擋住了 >_<**因此千萬別這樣作。畫的過程當中別忘了將畫筆設置一些你須要的屬性。

好了,畫好以後,咱們來看看效果怎麼樣:字體

樣式出來了哈!可是設計的沒那麼好看,你們將就看一看哈>_<spa

而後咱們須要重寫onTouch事件,在裏面判斷用戶的一些行爲:設計

switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: //按下
        	   //恢復默認值
            setDefault();
            /**
             *判斷按下的點在哪一個宮格中
             */
            invalidate();//刷新界面
            return true;
        case MotionEvent.ACTION_UP: //彈起
            invalidate();//刷新界面
            /**
             *一次按下結束,返回點擊的數字
             */
            //恢復默認
            setDefault();
            return true;
        case MotionEvent.ACTION_CANCEL:  //取消
            //恢復默認值
            setDefault();
            return true;
    }
複製代碼

如上面僞代碼所示,我寫了一個方法來判斷按下的點在哪一個宮格中:code

private void handleDown(float x, float y) {
    if (y < mHeight / 2) {
        return;
    }
    if (x >= 10 && x <= 10 + mRectWidth) {   //第一列
        clickX = xs[0];
        if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(1)
            clickY = ys[0];
            x1 = 10;
            y1 = mHeight / 2 + 10;
            x2 = 10 + mRectWidth;
            y2 = mHeight / 2 + 10 + mRectHeight;
            number = "1";
        } else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(4)
            x1 = 10;
            y1 = mHeight / 2 + 20 + mRectHeight;
            x2 = 10 + mRectWidth;
            y2 = mHeight / 2 + 20 + 2 * mRectHeight;
            clickY = ys[1];
            number = "4";
        } else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(7)
            x1 = 10;
            y1 = mHeight / 2 + 30 + 2 * mRectHeight;
            x2 = 10 + mRectWidth;
            y2 = mHeight / 2 + 30 + 3 * mRectHeight;
            clickY = ys[2];
            number = "7";
        } else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(0)
            x1 = 10;
            y1 = mHeight / 2 + 40 + 3 * mRectHeight;
            x2 = 10 + mRectWidth;
            y2 = mHeight / 2 + 40 + 4 * mRectHeight;
            clickY = ys[3];
            number = ".";
        }
    } else if (x >= 20 + mRectWidth && x <= 20 + 2 * mRectWidth) {  //第二列
        clickX = xs[1];
        if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(2)
            x1 = 20 + mRectWidth;
            y1 = mHeight / 2 + 10;
            x2 = 20 + 2 * mRectWidth;
            y2 = mHeight / 2 + 10 + mRectHeight;
            clickY = ys[0];
            number = "2";
        } else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(5)
            x1 = 20 + mRectWidth;
            y1 = mHeight / 2 + 20 + mRectHeight;
            x2 = 20 + 2 * mRectWidth;
            y2 = mHeight / 2 + 20 + 2 * mRectHeight;
            clickY = ys[1];
            number = "5";
        } else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(8)
            x1 = 20 + mRectWidth;
            y1 = mHeight / 2 + 30 + 2 * mRectHeight;
            x2 = 20 + 2 * mRectWidth;
            y2 = mHeight / 2 + 30 + 3 * mRectHeight;
            clickY = ys[2];
            number = "8";
        } else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(0)
            x1 = 20 + mRectWidth;
            y1 = mHeight / 2 + 40 + 3 * mRectHeight;
            x2 = 20 + 2 * mRectWidth;
            y2 = mHeight / 2 + 40 + 4 * mRectHeight;
            clickY = ys[3];
            number = "0";
        }
    } else if (x >= 30 + 2 * mRectWidth && x <= 30 + 3 * mRectWidth) {   //第三列
        clickX = xs[2];
        if (y >= mHeight / 2 + 10 && y <= mHeight / 2 + 10 + mRectHeight) {  //第一排(3)
            x1 = 30 + 2 * mRectWidth;
            y1 = mHeight / 2 + 10;
            x2 = 30 + 3 * mRectWidth;
            y2 = mHeight / 2 + 10 + mRectHeight;
            clickY = ys[0];
            number = "3";
        } else if (y >= mHeight / 2 + 20 + mRectHeight && y <= mHeight / 2 + 20 + 2 * mRectHeight) {  //第二排(6)
            x1 = 30 + 2 * mRectWidth;
            y1 = mHeight / 2 + 20 + mRectHeight;
            x2 = 30 + 3 * mRectWidth;
            y2 = mHeight / 2 + 20 + 2 * mRectHeight;
            clickY = ys[1];
            number = "6";
        } else if (y >= mHeight / 2 + 30 + 2 * mRectHeight && y <= mHeight / 2 + 30 + 3 * mRectHeight) {  //第三排(9)
            x1 = 30 + 2 * mRectWidth;
            y1 = mHeight / 2 + 30 + 2 * mRectHeight;
            x2 = 30 + 3 * mRectWidth;
            y2 = mHeight / 2 + 30 + 3 * mRectHeight;
            clickY = ys[2];
            number = "9";
        } else if (y >= mHeight / 2 + 40 + 3 * mRectHeight && y <= mHeight / 2 + 40 + 4 * mRectHeight) { //第四排(刪除鍵)
            x1 = 30 + 2 * mRectWidth;
            y1 = mHeight / 2 + 40 + 3 * mRectHeight;
            x2 = 30 + 3 * mRectWidth;
            y2 = mHeight / 2 + 40 + 4 * mRectHeight;
            clickY = ys[3];
            number = "delete";
        }
    }
}
複製代碼

注:這個方法跟你以前計算出的宮格座標有關係,因此必定不要計算錯誤cdn

至此,咱們寫的差很少了,而後就是要提供一個接口,對外開放,方便用的時候調用,獲取到數字或者其餘信息:blog

public interface OnNumberClickListener {
    //回調點擊的數字
    public void onNumberReturn(String number);

    //刪除鍵的回調
    public void onNumberDelete();
}
複製代碼

在onTouch事件中使用:

case MotionEvent.ACTION_UP: //彈起
            invalidate();//刷新界面
            //一次按下結束,返回點擊的數字
            if (onNumberClickListener != null) {
                if (number != null) {
                    if (number.equals("delete")) {
                        onNumberClickListener.onNumberDelete();
                    } else {
                        onNumberClickListener.onNumberReturn(number);
                    }
                }
            }
            //恢復默認
            setDefault();
            return true;
複製代碼

而後咱們來看一下效果怎麼樣吧!

功能也實現了,但是強迫症很強的我看着很不舒服,不知道大家有沒有,好歹這也是一個鍵盤吧!按下彈起的效果都沒有(沒有改變按下的背景),在這裏咱們設置一個標誌位,按下彈起刷新界面就能夠了。在onTouch事件中改變該標識位的值,而後在onDraw方法中判斷該標識位便可:

onTouch方法中增長:

case MotionEvent.ACTION_DOWN: //按下
	type=0;
case MotionEvent.ACTION_UP: //彈起
	type=1;
複製代碼

onDraw方法增長:

if (clickX > 0 && clickY > 0) {
        if (type == 0) {  //按下刷新
            if (number.equals("delete")) {
                mPaint.setColor(Color.WHITE);
                canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);
                canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);
            } else {
                if (number.equals(".")) {
                    mPaint.setColor(Color.WHITE);
                } else {
                    mPaint.setColor(Color.GRAY);
                }
                canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);
                mPaint.setColor(Color.BLACK);
                mPaint.setTextSize(60);// 設置字體大小
                mPaint.setStrokeWidth(2);
                canvas.drawText(number, clickX, clickY, mPaint);
            }
        } else if (type == 1) {  //擡起刷新
            if (number.equals("delete")) {
                mPaint.setColor(Color.GRAY);
                canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);
                canvas.drawBitmap(mBpDelete, xs[2] - mWidthOfBp / 2 + 10, ys[3] - mHeightOfBp / 2 - 10, mPaint);
            } else {
                if (number.equals(".")) {
                    mPaint.setColor(Color.GRAY);
                } else {
                    mPaint.setColor(Color.WHITE);
                }
                canvas.drawRoundRect(x1, y1, x2, y2, 10, 10, mPaint);
                mPaint.setColor(Color.BLACK);
                mPaint.setTextSize(60);// 設置字體大小
                mPaint.setStrokeWidth(2);
                canvas.drawText(number, clickX, clickY, mPaint);
            }
            //繪製完成後,重置
            clickX = 0;
            clickY = 0;
        }
    }
複製代碼

接下來再來看看效果吧:

如今看起來舒服多了,~_~

代碼我已經上傳到Github傳送門,歡迎你們fork,star

公衆號:Android技術經驗分享
相關文章
相關標籤/搜索