Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android仿斗魚領取魚丸文字驗證(二)

Android仿斗魚領取魚丸文字驗證(二)

編輯:關於Android編程

接著第一篇內容,來完成一下中間部分,中文驗證碼的部分,先看一下要實現的效果:

效果圖


一、分析功能

分析一下,我們要實現一個驗證碼功能,隨機生成4個中文組合,文字隨機,文字顏色隨機,文字會出現不同程度的旋轉,並且文字周圍會出現一些干擾項,點擊看不清時驗證碼內容會進行刷新重置.要解決的問題基本就這麼多,下面分步來解決一下.

(1)文字和文字顏色隨機,這個實現起來不難,只需要隨機產生一個中文,並且畫筆定義隨機的顏色即可.
(2)文字旋轉的話,可以通過旋轉畫布來完成該功能.
(3)對於干擾項,可以定義一個干擾項的數組,然後隨機取出裡邊的內容,在畫布上的隨機位置進行繪制即可.
(4)刷新重置這個做過很多遍,只需要重置一些變量,再去調用view的重繪方法即可.


二、代碼實現

通過上邊的分析,我們自定義一個CodeView來完成該功能.

先來定義一些自定義屬性,成員變量.代碼如下:

自定義屬性:
 

<code class="language-java hljs "><!--?xml version="1.0" encoding="utf-8"?-->
<resources>
    <!--CodeView相關-->
    <!--擾亂項的個數-->
    <attr format="integer" name="disturbSize">
    <!--干擾項文字的大小-->
    <attr format="dimension" name="disturbTextSize">
    <!--干擾項文字顏色-->
    <attr format="color" name="disturbTextColor">
    <!--驗證碼文字大小-->
    <attr format="dimension" name="codeTextSize">
    <!--驗證碼文字顏色-->
    <attr format="color" name="codeTextColor">
    <!--畫布旋轉的度數-->
    <attr format="integer" name="rotate">
    <declare-styleable name="CodeView">
        <attr name="disturbSize">
        <attr name="disturbTextSize">
        <attr name="disturbTextColor">
        <attr name="codeTextSize">
        <attr name="codeTextColor">
        <attr name="rotate">
        </code>

變量:

    /**
     * 干擾項
     */
    private final char[] CHARS = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };
    /**
     * 漢字畫筆
     */
    private Paint hzPaint;
    /**
     * 干擾項畫筆
     */
    private Paint dbPaint;
    /**
     * 漢字畫筆顏色
     */
    private int hzColor;
    /**
     * 干擾項畫筆顏色
     */
    private int dbColor;
    /**
     * 干擾項的個數,默認30個
     */
    private int DEFAULT_DBSIZE;
    /**
     * 默認畫筆顏色
     */
    private int DEFAULT_DBCOLOR, DEFAULT_HZCOLOR;
    /**
     * 干擾項隨機生成的位置
     */
    private float dbRandomX, dbRandomY;
    /**
     * 驗證碼文字
     */
    private List codeList;
    /**
     * 隨機
     */
    private Random random = new Random();
    /**
     * 矩形區域
     */
    private Rect mBounds;
    /**
     * 干擾文字大小
     */
    private int dbTextSize;
    /**
     * 驗證碼文字大小
     */
    private int hzTextSize;
    /**
     * 畫布旋轉度數,默認為6
     */
    private int rotate;

    public CodeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取自定義屬性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CodeView);
        DEFAULT_DBSIZE = ta.getInteger(R.styleable.CodeView_disturbSize, 30);
        dbTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_disturbTextSize, 10));
        hzTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_codeTextSize, 20));
        DEFAULT_DBCOLOR = ta.getColor(R.styleable.CodeView_disturbTextColor, 0);
        DEFAULT_HZCOLOR = ta.getColor(R.styleable.CodeView_codeTextColor, 0);
        rotate = ta.getInteger(R.styleable.CodeView_rotate, 6);
        init();

    }

通過分析我們知道,我們需要隨機生成一個中文,然後還要隨機生成文字的顏色,所以先來寫一個工具類Util,方便之後的使用.

工具類:

package com.example.junweiliu.hanzicode;

import android.graphics.Color;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridView;
import android.widget.ListAdapter;

import java.io.UnsupportedEncodingException;
import java.util.Random;

/**
 * Created by junweiliu on 16/5/9.
 */
public class Util {


    /**
     * 獲取隨機的顏色
     *
     * @return
     */
    public static int randomColor() {
        int red = (int) (Math.random() * 256);
        int green = (int) (Math.random() * 256);
        int blue = (int) (Math.random() * 256);
        return Color.argb(255, red, green, blue);
    }

    /**
     * 獲取隨機的暗色
     *
     * @return
     */
    public static int randomDarkColor() {
        int red = (int) (Math.random() * 100 + 56);
        int green = (int) (Math.random() * 100 + 56);
        int blue = (int) (Math.random() * 100 + 56);
        return Color.argb(255, red, green, blue);
    }

    /**
     * 獲取指定長度隨機簡體中文
     *
     * @param len int
     * @return String
     */
    public static String getRandomJianHan(int len) {
        String ret = "";
        for (int i = 0; i < len; i++) {
            String str = null;
            int hightPos, lowPos; // 定義高低位
            Random random = new Random();
            hightPos = (176 + Math.abs(random.nextInt(39))); //獲取高位值
            lowPos = (161 + Math.abs(random.nextInt(93))); //獲取低位值
            byte[] b = new byte[2];
            b[0] = (new Integer(hightPos).byteValue());
            b[1] = (new Integer(lowPos).byteValue());
            try {
                str = new String(b, "GBk"); //轉成中文
            } catch (UnsupportedEncodingException ex) {
                ex.printStackTrace();
            }
            ret += str;
        }
        return ret;
    }
}

代碼不是很復雜,這裡定義了兩種顏色的獲取,使用的時候可以根據自己的需要來使用或者修改.

先來搞定干擾項的問題,干擾項已經定義過了,是一些數字和字母,隨機顏色的方法也寫在工具類了,之後就是去生成這些干擾項,生成之前,還需要隨機生成位置,然後去繪制在畫布上就可以了.

干擾項:


    /**
     * 創建干擾項
     *
     * @return
     */
    private String createDBCode() {
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < DEFAULT_DBSIZE; i++) {
            buffer.append(CHARS[random.nextInt(CHARS.length)]);
        }
        return buffer.toString();
    }

    /**
     * 隨機生成干擾項畫筆樣式
     */
    private void randomDBStyele() {
        if (0 == DEFAULT_DBCOLOR) {
            dbColor = Util.randomDarkColor();
        } else {
            dbColor = DEFAULT_DBCOLOR;
        }
        dbPaint = new Paint();
        dbPaint.setColor(dbColor);
        dbPaint.setTextSize(dbTextSize);
    }

    /**
     * 隨機生成干擾項的顯示位置
     */
    private void randomDBPosition() {
        dbRandomX = (float) Math.random() * getWidth();
        dbRandomY = (float) Math.random() * getHeight();
    }

    /**
    * 繪制
    */ 
    @Override
    protected void onDraw(Canvas canvas) {

        Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bp);
        String dbCode = createDBCode();
        // 繪制干擾項
        for (int i = 0; i < dbCode.length(); i++) {
            randomDBStyele();
            randomDBPosition();
            c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
        }
        canvas.drawBitmap(bp, 0, 0, dbPaint);
    }

然後來看一下驗證文字,我們對外提供一個設置驗證文字的方法,因為這些需要驗證的文字肯定不是固定的,所以需要提供一個方法,來隨時改變這些驗證文字,獲取到這些驗證文字之後,就可以去繪制了.

驗證文字:

    /**
     * 設置驗證碼文字
     *
     * @param codes
     */
    public void setCode(List codes) {
        this.codeList = codes;
        invalidate();
    }

    /**
     * 隨機生成漢字畫筆樣式
     */
    private void randomHZStyle() {
        hzPaint = new Paint();
        hzPaint.setColor(hzColor);
        hzPaint.setFakeBoldText(random.nextBoolean());
        hzPaint.setTextSize(hzTextSize);
        hzPaint.getTextBounds("一", 0, "一".length(), mBounds);
    }

    /**
    * 繪制
    */ 
    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bp);
        String dbCode = createDBCode();
        // 繪制干擾項
        for (int i = 0; i < dbCode.length(); i++) {
            randomDBStyele();
            randomDBPosition();
            c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
        }
        canvas.drawBitmap(bp, 0, 0, dbPaint);
        // 繪制驗證文字
        if (null != codeList && codeList.size() > 0) {
            for (int i = 0; i < codeList.size(); i++) {
                randomHZStyle();
                canvas.save();
                canvas.rotate((int) (Math.floor(Math.random() * rotate + 1)
                        - Math.floor(Math.random() * rotate * 2 + 1)));
                canvas.drawText(codeList.get(i), mBounds.width() * (i + 1), getHeight() / 2 + mBounds.height() / 2, hzPaint);
                canvas.restore();
            }
        }
    }

繪制驗證文字的時候需要注意一下,這裡只是對畫布進行了一個旋轉操作,如果需要設計不同的效果,可以去添加修改這部分,如果需要特殊字體,也可以在初始化的時候去加載一些特殊字體,這裡就不去做這些內容了.

最後就是對外提供一個重置的方法,很簡單

    /**
     * 重置
     */
    public void reSet(List codes) {
        // 重置漢字畫筆顏色
        if (0 == DEFAULT_HZCOLOR) {
            hzColor = Util.randomDarkColor();
        } else {
            hzColor = DEFAULT_HZCOLOR;
        }
        this.codeList.clear();
        this.codeList = codes;
        invalidate();
    }

三、完整代碼實及現

CodeView:

package com.example.junweiliu.hanzicode;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ImageView;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by junweiliu on 16/5/9.
 */
public class CodeView extends ImageView {
    /**
     * 干擾項
     */
    private final char[] CHARS = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
    };
    /**
     * 漢字畫筆
     */
    private Paint hzPaint;
    /**
     * 干擾項畫筆
     */
    private Paint dbPaint;
    /**
     * 漢字畫筆顏色
     */
    private int hzColor;
    /**
     * 干擾項畫筆顏色
     */
    private int dbColor;
    /**
     * 干擾項的個數,默認30個
     */
    private int DEFAULT_DBSIZE;
    /**
     * 默認畫筆顏色
     */
    private int DEFAULT_DBCOLOR, DEFAULT_HZCOLOR;
    /**
     * 干擾項隨機生成的位置
     */
    private float dbRandomX, dbRandomY;
    /**
     * 驗證碼文字
     */
    private List codeList;
    /**
     * 隨機
     */
    private Random random = new Random();
    /**
     * 矩形區域
     */
    private Rect mBounds;
    /**
     * 干擾文字大小
     */
    private int dbTextSize;
    /**
     * 驗證碼文字大小
     */
    private int hzTextSize;
    /**
     * 畫布旋轉度數,默認為6
     */
    private int rotate;


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

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

    ;

    public CodeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // 獲取自定義屬性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CodeView);
        DEFAULT_DBSIZE = ta.getInteger(R.styleable.CodeView_disturbSize, 30);
        dbTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_disturbTextSize, 10));
        hzTextSize = DisplayUtil.sp2px(context, ta.getDimensionPixelSize(R.styleable.CodeView_codeTextSize, 20));
        DEFAULT_DBCOLOR = ta.getColor(R.styleable.CodeView_disturbTextColor, 0);
        DEFAULT_HZCOLOR = ta.getColor(R.styleable.CodeView_codeTextColor, 0);
        rotate = ta.getInteger(R.styleable.CodeView_rotate, 6);
        init();

    }

    /**
     * 初始化
     */
    private void init() {
        // 驗證的文字顏色一致,只需要生成一次
        if (0 == DEFAULT_HZCOLOR) {
            hzColor = Util.randomDarkColor();
        } else {
            hzColor = DEFAULT_HZCOLOR;
        }
        mBounds = new Rect();
        codeList = new ArrayList();

    }

    @Override
    protected void onDraw(Canvas canvas) {

        Bitmap bp = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas c = new Canvas(bp);
        String dbCode = createDBCode();
        // 繪制干擾項
        for (int i = 0; i < dbCode.length(); i++) {
            randomDBStyele();
            randomDBPosition();
            c.drawText(dbCode.charAt(i) + "", dbRandomX, dbRandomY, dbPaint);
        }
        canvas.drawBitmap(bp, 0, 0, dbPaint);
        // 繪制驗證文字
        if (null != codeList && codeList.size() > 0) {
            for (int i = 0; i < codeList.size(); i++) {
                randomHZStyle();
                canvas.save();
                canvas.rotate((int) (Math.floor(Math.random() * rotate + 1)
                        - Math.floor(Math.random() * rotate * 2 + 1)));
                canvas.drawText(codeList.get(i), mBounds.width() * (i + 1), getHeight() / 2 + mBounds.height() / 2, hzPaint);
                canvas.restore();
            }
        }
//        super.onDraw(canvas);
    }

    /**
     * 重置
     */
    public void reSet(List codes) {
        // 重置漢字畫筆顏色
        if (0 == DEFAULT_HZCOLOR) {
            hzColor = Util.randomDarkColor();
        } else {
            hzColor = DEFAULT_HZCOLOR;
        }
        this.codeList.clear();
        this.codeList = codes;
        invalidate();
    }

    /**
     * 設置驗證碼文字
     *
     * @param codes
     */
    public void setCode(List codes) {
        this.codeList = codes;
        invalidate();
    }

    /**
     * 隨機生成漢字畫筆樣式
     */
    private void randomHZStyle() {
        hzPaint = new Paint();
//        hzPaint.setAntiAlias(true);
        hzPaint.setColor(hzColor);
        hzPaint.setFakeBoldText(random.nextBoolean());
        hzPaint.setTextSize(hzTextSize);
        hzPaint.getTextBounds("一", 0, "一".length(), mBounds);
    }


    /**
     * 隨機生成干擾項畫筆樣式
     */
    private void randomDBStyele() {
        if (0 == DEFAULT_DBCOLOR) {
            dbColor = Util.randomDarkColor();
        } else {
            dbColor = DEFAULT_DBCOLOR;
        }
        dbPaint = new Paint();
//        dbPaint.setAntiAlias(true);
        dbPaint.setColor(dbColor);
        dbPaint.setTextSize(dbTextSize);
    }

    /**
     * 隨機生成干擾項的顯示位置
     */
    private void randomDBPosition() {
        dbRandomX = (float) Math.random() * getWidth();
        dbRandomY = (float) Math.random() * getHeight();
    }

    /**
     * 創建干擾項
     *
     * @return
     */
    private String createDBCode() {
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < DEFAULT_DBSIZE; i++) {
            buffer.append(CHARS[random.nextInt(CHARS.length)]);
        }
        return buffer.toString();
    }

}

xml:

<code class="language-java hljs ">

<linearlayout android:gravity="center" android:id="@+id/ll_all" android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" tools:context="com.example.junweiliu.hanzicode.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:hz="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools">

    <linearlayout android:background="@mipmap/hz_nor_ng" android:layout_height="wrap_content" android:layout_width="280dp" android:orientation="vertical" android:padding="20dp">
        <linearlayout android:gravity="center" android:layout_height="wrap_content" android:layout_margintop="10dp" android:layout_width="match_parent" android:orientation="horizontal" android:visibility="visible">
            <com.example.junweiliu.hanzicode.codeview android:id="@+id/cv_hz" android:layout_height="40dp" android:layout_width="120dp">

            </com.example.junweiliu.hanzicode.codeview></linearlayout></linearlayout></linearlayout></code><button android:background="@null" android:id="@+id/btn_reset" android:layout_height="wrap_content" android:layout_marginleft="10dp" android:layout_width="wrap_content" android:text="看不清?" android:textcolor="#4791FF" android:textsize="14sp"><code class="language-java hljs ">
        
    
</code></button>

MainActivity:

package com.example.junweiliu.hanzicode;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.graphics.ColorUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.Toast;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class MainActivity extends Activity {
    /**
     * 驗證碼
     */
    private CodeView mCodeView;
    /**
     * 重置按鈕
     */
    private Button mResetBtn;
    /**
     * 正確答案
     */
    private List mCorrectList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }

    /**
     * 初始化數據
     */
    private void initData() {
        mCorrectList = new ArrayList();
        // 添加文字
        for (int i = 0; i < 4; i++) {
            mCorrectList.add(Util.getRandomJianHan(1));
        }
    }

    /**
     * 初始化控件
     */
    private void initView() {        
        mCodeView = (CodeView) findViewById(R.id.cv_hz);
        mCodeView.setCode(mCorrectList);
        mResetBtn = (Button) findViewById(R.id.btn_reset);
        mResetBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 重置文字
                initData();
                // 刷新驗證碼
                mCodeView.reSet(mCorrectList);
            }
        }); 
     } 
}  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved