1. 程式人生 > >自定義View之驗證碼控制元件

自定義View之驗證碼控制元件

先上圖鎮貼

最近專案中有需要驗證碼,不過Android端的驗證碼一般都是手機簡訊,點選獲取驗證碼,將請求向後臺以及向簡訊驗證碼平臺傳送。簡訊平臺將驗證碼傳送到前端及後臺,讓前端輸入驗證碼和後臺進行比較。驗證碼的存在就是提高安全性,即使拿到賬戶和密碼,也無法登陸。因為驗證碼是隨機性的,唯一的,所以,提高了安全性。

但是,我們專案沒有要求簡訊驗證,因為賬戶不是手機號。所以,圖片驗證碼就很有必要了。後臺生成隨機數,我再轉換成圖片的形式,給使用者看到,讓使用者輸入,和後臺進行比較。相對來說,比較簡單。但是也提高了安全性。廢話少說,上程式碼。

我先說說我的思路,一般的圖片驗證碼都有純英文,英文加數字,純數字等幾種。我沒要求太複雜的,只用了純數字的那種,實現起來比較簡單。

首先,我需要知道,圖片驗證碼的樣式,如圖     大概就是這種樣式的。

好了,定義了樣式,就好做了。首先定義一個類,並讓它繼承View重寫onDraw方法。

定義畫筆,首先畫一個矩形

        //初始化畫筆
        paint.setColor(ColorUtil.AZURE);//設定畫筆顏色
        //繪製矩形背景
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

顏色自定義就可以,我使用的顏色值是#F0FFFF。其次就是定義矩形中間的文字了

        //如何設定不同字元的不同大小,不同顏色
        paint.setColor(randomColor());//設定畫筆顏色
        paint.setTextSize(randomTextSize());//設定文字大小
        //繪製數字/文字
        canvas.drawText(codes, getWidth, getHeight, paint);

我考慮到,驗證碼圖片,每一個字型顏色不一,大小不一,位置不同。所以,我將其顏色,大小,位置設定成動態。

randomColor()方法程式碼: rate預設為1;

        int red = random.nextInt(256) / rate;
        int green = random.nextInt(256) / rate;
        int blue = random.nextInt(256) / rate;
        return Color.rgb(red, green, blue);

randomTextSize()方法程式碼:size預設為1

        int textSize = random.nextInt(150) / size;
        if (textSize >= 80)
            return textSize;
        return 80;

準備工作完成,該寫資料來源了,因為我需要的驗證碼是四位數。如果是隨機數,我將隨機數設為10000,它最大不會超過四位數。給自定義View設一個點選事件,每點選一次讓資料來源變一次,這樣就成功得到了隨機數,驗證碼雛形。如果不是隨機數,則將字串個數控制在四位

        //獲取資料來源
        int i = random.nextInt(10000);

但是,我發現了一個問題,因為是隨機數0-10000之間的,所以有可能會出現三位數倆位數,甚至是一位數,並且這樣出來的隨機數展示出來,無論怎麼樣變,它們的顏色都是一樣的,因為它們是一個整體,所以我需要將這個整數進行拆分。如果是四位數,按照千位,百位,十位,個位進行拆分。如果是三位數,則千位為0,如果是兩位數,則千位與百位分別為0.以此類推;我很有必要將它們拆開。由於語言的除法的特殊性,我們可以進行單獨求數,首先先得到千位上的數,然後在得到百位上的數,如果不存在,則為0。之後做了一些改動,之前只能使用隨機數,這次改動可以使用任意字串包括隨機數了,但是,隨機數有可能會隨機三位數、兩位數、一位數甚至是負數,這就需要我們進行處理了。很簡單,做一個判斷,如果是純數字,則就認為是隨機數(驗證碼必須保證是四位哦)否則認為是字串。

private String[] subString(Object codes) {
        String strCodes = setValueOf(codes);
        if (isInteger(codes)) {//判斷是純數字
            int thousand = getThousand(strCodes);//千位
            int hundred = getHundred(strCodes);//百位
            int ten = getTen(strCodes);//十位
            int one = getOne(strCodes);//個位
            String thousands = setValueOf(thousand);
            String hundreds = setValueOf(hundred);
            String tens = setValueOf(ten);
            String ones = setValueOf(one);
            return new String[]{thousands, hundreds, tens, ones};
        } else {//判斷不是純數字
            if (strCodes.length() > 0) {
                c1 = strCodes.substring(0, 1);
                c2 = strCodes.substring(1, 2);
                c3 = strCodes.substring(2, 3);
                c4 = strCodes.substring(3, 4);
            }
            return new String[]{c1, c2, c3, c4};
        }

    }

很簡單,將初始值設為 4602 舉例子。4602/1000我們得到4,4是千位,假如我的資料來源為三位數,千位上沒有,我們就得到0。

(number - thousand * 1000) / 100我們先計算number - thousand * 1000 我們已經得到thousand為4,4*1000得到4000,number為初始值4602,兩者相減得到602,我們在使用602/100得到6,6是百位;我們用這種方法分別得到初始值的千位,百位,十位,個位;

我們在分別給每一個數字進行繪製,我們就能繪製出不同顏色,大小的隨機數了。

改動,將原來的設定驗證碼大小顏色等放在外部,防止UI重新整理,導致檢視重新整理。

/**
     * 設定字型內容,顏色以及位置
     *
     * @param codes     驗證碼內容
     * @param getWidth  驗證碼距離寬度
     * @param getHeight 驗證碼距離高度
     * @param canvas    畫布
     * @param paint     畫筆
     */
    private void drawText(String codes, int getWidth, int getHeight, Canvas canvas, Paint paint) {
        // 繪製數字/文字
        canvas.drawText(codes, getWidth, getHeight, paint);
    }

解決這些問題,基本上整個控制元件就完成了。但是會發現,一般的驗證碼圖會有一些干擾線,我們還缺少干擾線,上程式碼

同樣,干擾線,顏色,大小寫在外部,防止UI重新整理時,導致檢視重新整理。

 /**
     * 設定干擾線
     * @param canvas  畫布
     * @param paint   畫筆
     * @param startX  起點X座標
     * @param startY  起點Y座標
     * @param stopX   終點X座標
     * @param stopY   終點Y座標
     * @param strokeWidth 干擾線寬度
     */
    private void drawLine(Canvas canvas, Paint paint, int startX, int startY, int stopX, int stopY, int strokeWidth) {
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

將驗證碼顏色,大下等屬性放在設定驗證碼的時候,進行賦值,防止,每次更新UI同時,導致驗證碼檢視的更新

/**
     * 設定驗證碼的顏色大小
     */
    private void setVerificationCodeStyle(){
        /**
         * 設定干擾線
         */
        startX = random.nextInt(NEXTINTWIDTH_ONE);
        startY = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX = random.nextInt(NEXTINTWIDTH_THREE);
        stopY = random.nextInt(NEXTINTHEIGHT_TWO);
        startX1 = random.nextInt(NEXTINTWIDTH_ONE);
        startY1 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX1 = random.nextInt(NEXTINTWIDTH_TWO);
        stopY1 = random.nextInt(NEXTINTHEIGHT_TWO);
        startX2 = random.nextInt(NEXTINTWIDTH_THREE);
        startY2 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX2 = random.nextInt(NEXTINTWIDTH_TWO);
        stopY2 = random.nextInt(NEXTINTWIDTH_TWO);
        startX3 = random.nextInt(NEXTINTWIDTH_ONE);
        startY3 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX3 = random.nextInt(NEXTINTWIDTH_THREE);
        stopY3 = random.nextInt(NEXTINTHEIGHT_TWO);
        startX4 = random.nextInt(NEXTINTWIDTH_ONE);
        startY4 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX4 = random.nextInt(NEXTINTWIDTH_THREE);
        stopY4 = random.nextInt(NEXTINTHEIGHT_TWO);

        /**
         * 設定驗證碼顏色
         */
        color = randomColor();
        color2 = randomColor();
        color3 = randomColor();
        color4 = randomColor();

        /**
         * 設定驗證碼字型大小
         */
        size = randomTextSize();
        size2 = randomTextSize();
        size3 = randomTextSize();
        size4 = randomTextSize();
    }

通過線形繪製,繪製干擾線。這樣基本上一個驗證碼控制元件已經完成了,我們再做一些細節的調整

同時,還進行了大小寫的判斷,進行大小寫區別

 /**
     * 判斷輸入內容是否與展示內容相同
     * Equality相等
     *
     * @param charSequence
     * @return
     */
    public boolean isEquality(String charSequence, boolean isOpen) {
        String sequenceCode = null;//輸入框輸入內容
        String stringCode = null;//驗證碼隨機數字
        if (null == charSequence || "".equals(charSequence)) {//判斷輸入內容為null
            if (onEqResultListener != null)
                onEqResultListener.onNull();
            return false;
        } else {//判斷輸入內容不為null
            if (isOpen) {//開啟大小寫區別
                sequenceCode = charSequence;
                stringCode = getCodeString();
            } else {//關閉大小寫區別
                sequenceCode = charSequence.toLowerCase();//大寫轉小寫
                stringCode = getCodeString().toLowerCase();//大寫轉小寫
            }
            if (stringCode.equals(sequenceCode)) {//判斷輸入內容與隨機數相等
                if (onEqResultListener != null)
                    onEqResultListener.onSuccess();
                return true;
            } else {//判斷輸入內容與隨機數不相等
                onEqResultListener.onError();
                return false;
            }
        }
    }

使用String型別自帶的大小寫轉換器進行轉換,如果不開啟大小寫區別,則將輸入的字串與驗證碼中的字串,全部轉換為小寫。

if (isOpen) {//開啟大小寫區別
                sequenceCode = charSequence;
                stringCode = getCodeString();
            } else {//關閉大小寫區別
                sequenceCode = charSequence.toLowerCase();//大寫轉小寫
                stringCode = getCodeString().toLowerCase();//大寫轉小寫
            }


整體程式碼,在此借用大佬的"點點"背景樣式,如圖   

https://blog.csdn.net/ydxlt/article/details/50786076

public class VerificationView extends View {
    private static final String TAG = "VerificationView";

    /**
     * int min=10;
     * int max=99;
     * Random random = new Random();
     * int num = random.nextInt(max)%(max-min+1) + min;
     */
    private Object setCodes;//外部設定的驗證碼

    private Object code;
    private Random random;//隨機數

    private Paint paint;//畫筆
    private Rect rect;//定義矩形結構

    //干擾線
    private final int DISTURB_WIDTH = 200;
    private final int DISTURB_HEIGHT = 80;
    private final int STROKE_WIDTH = 1;

    private final int NEXTINTWIDTH_ONE = DISTURB_WIDTH / 1;
    private final int NEXTINTWIDTH_TWO = DISTURB_WIDTH * 2;
    private final int NEXTINTWIDTH_THREE = DISTURB_WIDTH / 1 * 2;

    private final int NEXTINTHEIGHT_ONE = DISTURB_HEIGHT / 1 * 2;
    private final int NEXTINTHEIGHT_TWO = DISTURB_HEIGHT / 1;

    //判斷結果回撥
    private OnEqResultListener onEqResultListener;
    private boolean isOpen;
    //int型驗證碼
    private int i;
    //驗證碼陣列
    private String[] codesArray;
    //得到單個驗證碼
    private String c1;
    private String c2;
    private String c3;
    private String c4;
    private int DISTINGUISH;
    private int min = 1;
    private int max = 99;
    private boolean isRefereshing;
    //干擾條
    private int startX;
    private int startY;
    private int stopX;
    private int stopY;
    private int startX1;
    private int startY1;
    private int stopX1;
    private int stopY1;
    private int startX2;
    private int startY2;
    private int stopX2;
    private int stopY2;
    private int startX3;
    private int startY3;
    private int stopX3;
    private int stopY3;
    private int startX4;
    private int startY4;
    private int stopX4;
    private int stopY4;
    private int color1;
    private int color2;
    private int color3;
    private int color4;
    private int size;
    private int size2;
    private int size3;
    private int size4;
    private Paint mPointPaint;
    private List<PointF> mPoints = new ArrayList();

    //字型寬度
    public VerificationView(Context context) {
        this(context, null);
    }

    public VerificationView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VerificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //建立畫筆
        //Paint.ANTI_ALIAS_FLAG 抗鋸齒
        if (paint == null)
            paint = new Paint(Paint.ANTI_ALIAS_FLAG);

        // 初始化干擾點畫筆
        if (mPointPaint == null)
            mPointPaint = new Paint();

        mPointPaint.setStrokeWidth(6);
        mPointPaint.setStrokeCap(Paint.Cap.ROUND); // 設定斷點處為圓形

        //定義矩形結構
        if (rect == null)
            rect = new Rect();
        //隨機數
        if (random == null)
            random = new Random();
    }

    /**
     * 繪製
     *
     * @param canvas 畫布
     */
    @Override
    protected void onDraw(Canvas canvas) {
        //獲取到驗證碼
        code = getVerificationCodes();
        setDraws(canvas, isRefereshing);
        isRefereshing = true;
        //super.onDraw(canvas);
    }

    /**
     * 拆分
     *
     * @param codes 驗證碼字串
     * @return
     */
    private String[] subString(Object codes) {
        String strCodes = setValueOf(codes);
        if (isInteger(codes)) {//判斷是純數字
            int thousand = getThousand(strCodes);//千位
            int hundred = getHundred(strCodes);//百位
            int ten = getTen(strCodes);//十位
            int one = getOne(strCodes);//個位
            String thousands = setValueOf(thousand);
            String hundreds = setValueOf(hundred);
            String tens = setValueOf(ten);
            String ones = setValueOf(one);
            return new String[]{thousands, hundreds, tens, ones};
        } else {//判斷不是純數字
            if (strCodes.length() > 0) {
                c1 = strCodes.substring(0, 1);
                c2 = strCodes.substring(1, 2);
                c3 = strCodes.substring(2, 3);
                c4 = strCodes.substring(3, 4);
            }
            return new String[]{c1, c2, c3, c4};
        }
    }

    /**
     * 繪製
     *
     * @param canvas
     */
    private void setDraws(Canvas canvas, boolean refereshing) {

        mPoints.clear();
        // 生成干擾點座標
        for (int i = 0; i < 150; i++) {
            PointF pointF = new PointF(random.nextInt(getWidth()) + 10, random.nextInt(getHeight()) + 10);
            mPoints.add(pointF);
        }


        // 產生干擾效果1 -- 干擾點
        for (PointF pointF : mPoints) {
            mPointPaint.setARGB(255, random.nextInt(200) + 20, random.nextInt(200) + 20, random.nextInt(200) + 20);
            canvas.drawPoint(pointF.x, pointF.y, mPointPaint);
        }


        //設定亞畫素
        paint.setSubpixelText(true);
        paint.setAntiAlias(true);

        //初始化畫筆
        paint.setColor(ColorUtil.AZURE);//設定畫筆顏色
        //繪製矩形背景
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);


        paint.setColor(color1);
        //繪製畫筆抗鋸齒
        //設定干擾條 DISTURB_WIDTH / 1 ,  DISTURB_HEIGHT / 1 * 2
        drawLine(canvas, paint, startX, startY, stopX, stopY, STROKE_WIDTH + 1);

        paint.setColor(color2);
        //設定干擾條 DISTURB_WIDTH / 1 * 2 ,  DISTURB_HEIGHT / 1 * 2
        drawLine(canvas, paint, startX1, startY1, stopX1, stopY1, STROKE_WIDTH + 2);

        paint.setColor(color3);
        //設定干擾條 DISTURB_WIDTH / 1 ,  DISTURB_HEIGHT / 1 * 2
        drawLine(canvas, paint, startX2, startY2, stopX2, stopY2, STROKE_WIDTH + 1);

        paint.setColor(color4);
        //設定干擾條  DISTURB_WIDTH * 2 , DISTURB_HEIGHT / 1
        drawLine(canvas, paint, startX3, startY3, stopX3, stopY3, STROKE_WIDTH + 3);

        paint.setColor(color3);
        //設定干擾條  DISTURB_WIDTH / 1 * 2 , DISTURB_HEIGHT / 1
        drawLine(canvas, paint, startX4, startY4, stopX4, stopY4, STROKE_WIDTH + 2);


        //設定內邊距
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();


        rect.left = 50 + paddingLeft;
        rect.top = 66 + paddingTop;
        rect.right = 50 + paddingRight;
        rect.bottom = 0 + paddingBottom;

        //獲取到單個驗證碼
        codesArray = subString(code);

        for (int i = 0; i < 4; i++) {
            paint.getTextBounds(codesArray[i], 0, codesArray[i].length(), rect);
        }

        //設定畫筆的樣式
        paint.setStyle(Paint.Style.STROKE);//空心
        //如何設定不同字元的不同大小,不同顏色
        paint.setColor(color1);//設定畫筆顏色
        paint.setTextSize(size);//設定文字大小
        //設定內容、大小、顏色
        drawText(codesArray[0], getWidth() / 2 - rect.width() / 2 - 100, getHeight() / 2 + rect.height() / 2 + 10, canvas, paint);

        paint.setColor(color2);//設定畫筆顏色
        paint.setTextSize(size2);//設定文字大小
        drawText(codesArray[1], getWidth() / 2 - rect.width() / 2 - 50, getHeight() / 2 + rect.height() / 2 + 10, canvas, paint);

        paint.setColor(color3);//設定畫筆顏色
        paint.setTextSize(size3);//設定文字大小
        drawText(codesArray[2], getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2 + 10, canvas, paint);

        paint.setColor(color4);//設定畫筆顏色
        paint.setTextSize(size4);//設定文字大小
        drawText(codesArray[3], getWidth() / 2 - rect.width() / 2 + 50, getHeight() / 2 + rect.height() / 2 + 10, canvas, paint);

    }

    /**
     * 外部設定驗證碼
     *
     * @param setCodes 驗證碼資料
     */
    public void setVerificationCodes(Object setCodes) {
        isRefereshing = false;
        if (setCodes.toString().length() < 4 || setCodes.toString().length() > 4) {//判斷當開發者將驗證碼個數設定小於4位或者大於4位則將展示預設驗證碼
            this.setCodes = "ZHLl";
            return;
        }
        this.setCodes = setCodes;

        setVerificationCodeStyle();


        invalidate();
    }

    /**
     * 設定驗證碼的顏色大小
     */
    private void setVerificationCodeStyle() {
        /**
         * 設定干擾線
         */
        startX = random.nextInt(NEXTINTWIDTH_ONE);
        startY = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX = random.nextInt(NEXTINTWIDTH_THREE);
        stopY = random.nextInt(NEXTINTHEIGHT_TWO);
        startX1 = random.nextInt(NEXTINTWIDTH_ONE);
        startY1 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX1 = random.nextInt(NEXTINTWIDTH_TWO);
        stopY1 = random.nextInt(NEXTINTHEIGHT_TWO);
        startX2 = random.nextInt(NEXTINTWIDTH_THREE);
        startY2 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX2 = random.nextInt(NEXTINTWIDTH_TWO);
        stopY2 = random.nextInt(NEXTINTWIDTH_TWO);
        startX3 = random.nextInt(NEXTINTWIDTH_ONE);
        startY3 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX3 = random.nextInt(NEXTINTWIDTH_THREE);
        stopY3 = random.nextInt(NEXTINTHEIGHT_TWO);
        startX4 = random.nextInt(NEXTINTWIDTH_ONE);
        startY4 = random.nextInt(NEXTINTHEIGHT_ONE);
        stopX4 = random.nextInt(NEXTINTWIDTH_THREE);
        stopY4 = random.nextInt(NEXTINTHEIGHT_TWO);

        /**
         * 設定驗證碼顏色
         */
        color1 = randomColor();
        color2 = randomColor();
        color3 = randomColor();
        color4 = randomColor();

        /**
         * 設定驗證碼字型大小
         */
        size = randomTextSize();
        size2 = randomTextSize();
        size3 = randomTextSize();
        size4 = randomTextSize();
    }

    /**
     * 得到驗證碼
     *
     * @return
     */
    public Object getVerificationCodes() {
        return setCodes;
    }

    /**
     * 設定字型顏色
     *
     * @return
     */
    private int randomColor() {
        return randomColor(1);
    }

    /**
     * 設定字型顏色
     *
     * @param rate
     * @return
     */
    private int randomColor(int rate) {
        int red = random.nextInt(256) / rate;
        int green = random.nextInt(256) / rate;
        int blue = random.nextInt(256) / rate;
        return Color.rgb(red, green, blue);
    }

    /**
     * 設定字型大小
     *
     * @return
     */
    private int randomTextSize() {
        return randomTextSize(1);
    }

    /**
     * 設定字型大小
     *
     * @param size
     * @return
     */
    private int randomTextSize(int size) {
        int textSize = random.nextInt(150) / size;
        if (textSize >= 80)
            return textSize;
        return 80;
    }

    /**
     * 獲取驗證碼框內容
     *
     * @return
     */
    public String getCodeString() {
        return getSetiingCodes(code);
    }

    /**
     * 獲取驗證框內容
     *
     * @param obCodes
     * @return
     */
    public String getSetiingCodes(Object obCodes) {
        String codes = setValueOf(obCodes);
        return codes;
    }

    /**
     * 求四位數之和
     *
     * @param number 資料來源初始值
     * @return
     */
    public int getSum(String number) {
        return getThousand(number) + getHundred(number) + getTen(number) + getOne(number);// 例如 4602 ~ 4+6+0+2=12
    }

    /**
     * 得到千位數
     *
     * @param numbers 資料來源初始值千位
     * @return
     */
    public int getThousand(String numbers) {  //例如 4602/1000=4//千位數
        int number = setParseInt(numbers);
        return number / 1000; //得到千位數;
    }

    /**
     * 得到百位數
     *
     * @param numbers 資料來源初始值百位
     * @return
     */
    public int getHundred(String numbers) {  //例如 4602-4*1000 = 602 602/100 = 6//百位數
        int number = setParseInt(numbers);
        return (number - getThousand(numbers) * 1000) / 100;//得到百位數;
    }

    /**
     * 得到十位數
     *
     * @param numbers 資料來源初始值十位
     * @return
     */
    public int getTen(String numbers) {  //例如 4602-4*1000-6*100=4602-4000-600=2/10=0//十位數
        int number = setParseInt(numbers);
        return (number - getThousand(numbers) * 1000 - getHundred(numbers) * 100) / 10;// 得到十位數;
    }

    /**
     * 得到個位數
     *
     * @param numbers 資料來源初始值個位
     * @return
     */
    public int getOne(String numbers) {
        //例如 4602-4*1000-6*100-0*10 = 4602-4000-600-0=2//個位數
        int number = setParseInt(numbers);
        return number - getThousand(numbers) * 1000 - getHundred(numbers) * 100 - getTen(numbers) * 10;// 求個位;
    }

    /**
     * 設定字型內容,顏色以及位置
     *
     * @param codes     驗證碼內容
     * @param getWidth  驗證碼距離寬度
     * @param getHeight 驗證碼距離高度
     * @param canvas    畫布
     * @param paint     畫筆
     */
    private void drawText(String codes, int getWidth, int getHeight, Canvas canvas, Paint paint) {
        // 繪製數字/文字
        canvas.drawText(codes, getWidth, getHeight, paint);
    }

    /**
     * 設定干擾線
     *
     * @param canvas      畫布
     * @param paint       畫筆
     * @param startX      起點X座標
     * @param startY      起點Y座標
     * @param stopX       終點X座標
     * @param stopY       終點Y座標
     * @param strokeWidth 干擾線寬度
     */
    private void drawLine(Canvas canvas, Paint paint, int startX, int startY, int stopX, int stopY, int strokeWidth) {
        paint.setStrokeWidth(strokeWidth);
        canvas.drawLine(startX, startY, stopX, stopY, paint);
    }

    /**
     * 將字串轉為int型
     *
     * @param text
     * @return
     */
    private int setParseInt(String text) {
        int i = Integer.parseInt(text);
        return i;
    }

    /**
     * 將Object型別轉換成String型別
     *
     * @param object
     * @return
     */
    private String setValueOf(Object object) {
        String string = String.valueOf(object);
        return string;
    }


    /**
     * 判斷輸入內容是否與展示內容相同
     * Equality相等
     *
     * @param charSequence
     * @return
     */
    public boolean isEquality(String charSequence, boolean isOpen) {
        String sequenceCode = null;//輸入框輸入內容
        String stringCode = null;//驗證碼隨機數字
        if (null == charSequence || "".equals(charSequence)) {//判斷輸入內容為null
            if (onEqResultListener != null)
                onEqResultListener.onNull();
            return false;
        } else {//判斷輸入內容不為null
            if (isOpen) {//開啟大小寫區別
                sequenceCode = charSequence;
                stringCode = getCodeString();
            } else {//關閉大小寫區別
                sequenceCode = charSequence.toLowerCase();//大寫轉小寫
                stringCode = getCodeString().toLowerCase();//大寫轉小寫
            }
            if (stringCode.equals(sequenceCode)) {//判斷輸入內容與隨機數相等
                if (onEqResultListener != null)
                    onEqResultListener.onSuccess();
                return true;
            } else {//判斷輸入內容與隨機數不相等
                onEqResultListener.onError();
                return false;
            }
        }
    }


    /**
     * 判斷輸入內容是否與展示內容相同
     * Equality相等
     *
     * @param text
     * @return
     */
    public boolean isEquality(TextView text, boolean isOpen) {
        String charSequence = getTextToString(text);
        boolean equality = isEquality(charSequence, isOpen);
        return equality;
    }

    /**
     * 得到輸入框輸入的字串
     *
     * @param textView
     * @return
     */
    public String getTextToString(TextView textView) {
        return textView == null || "".equals(textView.getText().toString().trim()) ? "" : textView.getText().toString().trim();
    }

    /**
     * 結果回撥方法
     * result 結果
     *
     * @param charSequence
     * @param onEqResultListener
     */
    public void setEqOnResult(String charSequence, OnEqResultListener onEqResultListener) {
        this.onEqResultListener = onEqResultListener;
        isEquality(charSequence, isOpen());
    }

    /**
     * 結果回撥方法
     * result 結果
     *
     * @param textView
     * @param onEqResultListener
     */
    public void setEqOnResult(TextView textView, OnEqResultListener onEqResultListener) {
        this.onEqResultListener = onEqResultListener;
        isEquality(textView, isOpen());
    }

    /**
     * 設定是否開啟大小寫區別
     *
     * @param isOpen
     */
    public void setOpenDifference(boolean isOpen) {
        this.isOpen = isOpen;
    }

    /**
     * 返回是否開啟大小寫區別
     *
     * @return
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * 判斷是否是純數字
     *
     * @param str
     * @return
     */
    public boolean isInteger(Object str) {
        String s = setValueOf(str);
        Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
        return pattern.matcher(s).matches();
    }

    //清空物件
    public void onDestroy() {
        if (paint != null)
            paint = null;
        if (rect != null)
            rect = null;
        if (random != null)
            random = null;
    }

    public interface OnEqResultListener {
        //驗證碼對比成功
        void onSuccess();

        //驗證碼對比失敗
        void onError();

        //對比驗證碼為null
        void onNull();
    }

    /**
     * 把view轉成圖片
     *
     * @param view
     */
    private void viewSaveToImage(View view) {
        view.setDrawingCacheEnabled(true);
        view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        view.setDrawingCacheBackgroundColor(Color.WHITE);

        // 把一個View轉換成圖片
        Bitmap cachebmp = viewConversionBitmap(view);

//        if (mBitmapDoneListener != null){
//            mBitmapDoneListener.bitmapDone(cachebmp);
//        }

        view.destroyDrawingCache();
    }

    /**
     * view轉bitmap
     */
    public Bitmap viewConversionBitmap(View v) {
        int w = v.getWidth();
        int h = v.getHeight();

        Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmp);

        c.drawColor(Color.WHITE);
        /** 如果不設定canvas畫布為白色,則生成透明 */

        v.layout(0, 0, w, h);
        v.draw(c);

        return bmp;
    }

    /**
     * 將char直接轉化為byte,其值就是字元的ascii
     *
     * @param ch
     * @return
     */
    public byte charToByteAscii(char ch) {

        byte byteAscii = (byte) ch;

        return byteAscii;
    }

    /**
     * 將char直接轉化成為int,其值就是字元的ASCII碼
     *
     * @param ch
     * @return
     */
    public int charToIntegerAscii(char ch) {
        int intAscii = (int) ch;
        return intAscii;
    }

    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1)
    public Bitmap getBitmap(View view) {
        Bitmap bitmap = null;
        int width = view.getRight() - view.getLeft();
        int height = view.getBottom() - view.getTop();
        final boolean opaque = view.getDrawingCacheBackgroundColor() != 0 || view.isOpaque();
        Bitmap.Config quality;
        if (!opaque) {
            switch (view.getDrawingCacheQuality()) {
                case DRAWING_CACHE_QUALITY_AUTO:
                case DRAWING_CACHE_QUALITY_LOW:
                case DRAWING_CACHE_QUALITY_HIGH:
                default:
                    quality = Bitmap.Config.ARGB_8888;
                    break;
            }
        } else {
            quality = Bitmap.Config.RGB_565;
        }
        bitmap = Bitmap.createBitmap(getResources().getDisplayMetrics(),
                width, height, quality);
        bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
        if (opaque) bitmap.setHasAlpha(false);
        boolean clear = view.getDrawingCacheBackgroundColor() != 0;
        Canvas canvas = new Canvas(bitmap);
        if (clear) {
            bitmap.eraseColor(view.getDrawingCacheBackgroundColor());
        }
        view.computeScroll();
        final int restoreCount = canvas.save();
        canvas.translate(-view.getScrollX(), -view.getScrollY());
        view.draw(canvas);
        canvas.restoreToCount(restoreCount);
        canvas.setBitmap(null);
        return bitmap;
    }


    // 獲取指定Activity的截圖,儲存到png檔案
    public static Bitmap takeScreenShot(Activity activity) {
        // View是你需要截圖的View
        View view = activity.getWindow().getDecorView();
        view.setDrawingCacheEnabled(true);
        view.buildDrawingCache();
        Bitmap b1 = view.getDrawingCache();

        // 獲取狀態列高度
        Rect frame = new Rect();
        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
        int statusBarHeight = frame.top;

        // 獲取螢幕長和高
        int width = activity.getWindowManager().getDefaultDisplay().getWidth();
        int height = activity.getWindowManager().getDefaultDisplay().getHeight();
        // 去掉標題欄
        int hh = statusBarHeight + 50;

        Bitmap b = Bitmap.createBitmap(b1, 0, hh, width, height - hh);
        view.destroyDrawingCache();

        return b;
    }


    /**
     * 載入本地圖片
     *
     * @param url 本地圖片嗎路徑
     * @return
     */
    public Bitmap getLoacalBitmap(String url) {
        //獲取File檔案流物件
        FileInputStream fis = null;
        try {
            if (fis == null)
                fis = new FileInputStream(url);
            return BitmapFactory.decodeStream(fis);  ///把流轉化為Bitmap圖片

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private Bitmap loadBitmapFromView(View v) {
        int w = v.getWidth();
        int h = v.getHeight();
        Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bmp);

        c.drawColor(Color.WHITE);
        /** 如果不設定canvas畫布為白色,則生成透明 */

        v.layout(0, 0, w, h);
        v.draw(c);

        return bmp;
    }

    //然後View和其內部的子View都具有了實際大小,也就是完成了佈局,相當與新增到了介面上。接著就可以建立點陣圖並在上面繪製了:
    public void layoutView(View v, int width, int height) {
        // 指定整個View的大小 引數是左上角 和右下角的座標
        v.layout(0, 0, width, height);
        int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
        int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
        /** 當然,measure完後,並不會實際改變View的尺寸,需要呼叫View.layout方法去進行佈局。
         * 按示例呼叫layout函式後,View的大小將會變成你想要設定成的大小。
         */
        v.measure(measuredWidth, measuredHeight);
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    }

    //設定驗證碼的隨機字串
    public String getRandomString(Random random, int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

}

在外部的呼叫,相對簡單。我們需要再onCreate方法裡面將驗證碼控制元件初始化

        //初始化驗證碼字串
        String randomString = getRandomString(random, 4);
        //設定驗證碼源
        verificationView.setVerificationCodes(randomString);

getRandomString方法目的是設定隨機字串

    public String getRandomString(Random random, int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }

當然,將初始化的程式碼也可寫在驗證碼點選事件裡面,已便得到,點選驗證碼圖片,改變驗證碼字串的目的