Android自动生成验证码View,支持数字、字母、中文等不同验证码类型

验证码在网页应用中可以说应用十分广泛,但是我们在Android开发中有时候也是需要用到验证码的,其实验证码是一个最基础的自定义控件,原理非常的简单,接下来直接上代码

首先需要一些自定义的属性

<!--验证码控件自定义属性-->
<declare-styleable name="custom_Verification_Code">
    <!--验证码文字大小-->
    <attr name="codeTextSize" format="dimension|reference"/>
    <!--验证码长度-->
    <attr name="codeLength" format="integer|reference"/>
    <!--验证码类型-->
    <attr name="codeType">
        <!--纯数字-->
        <enum name="num" value="0"/>
        <!--字母-->
        <enum name="litter" value="1"/>
        <!--中文-->
        <enum name="chinese" value="2"/>
        <!--字母和数字混合-->
        <enum name="litterAndNum" value="3"/>
    </attr>
</declare-styleable>
这里要说一下codeType这个属性,是个枚举,也就是我们经常在其他View中使用的常量,这里如果你给codeType没有定义format属性的话,那么最好使用int类型,如果定义了其他属性,要在Java文件中做接收处理。

接下来看一个各个类型的验证码生成方法

/**
 * 生成纯字母
 * @return
 */
public String getLetter(){
    String val = "";
    Random random = new Random();
    int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
    val += (char)(random.nextInt(26) + temp);
    return val;
}


/**
 * 生成数字和字母
 * @return
 */
public String getLetterAndNum() {

    String val = "";
    Random random = new Random();
    int charOrNum = random.nextInt(2) % 2;
    //输出字母还是数字
    if( charOrNum==0 ) {
        //输出是大写字母还是小写字母
        int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
        val += (char)(random.nextInt(26) + temp);
    } {
        val += String.valueOf(random.nextInt(10));
    }
    return val;
}


/**
 * 生成随机汉字
 * @return
 */
private char getChineseChar() {
    String str = "";
    int hightPos;
    int lowPos;


    hightPos = (176 + Math.abs(random.nextInt(39)));
    lowPos = (161 + Math.abs(random.nextInt(93)));

    byte[] b = new byte[2];
    b[0] = (Integer.valueOf(hightPos)).byteValue();
    b[1] = (Integer.valueOf(lowPos)).byteValue();

    try {
        str = new String(b, "GBK");
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return str.charAt(0);
}
生成0到9数字就不贴出来了,这个应该很简单。

做好这些尊卑工作,那么首先我们要接收自定义属性,以及初始化画笔之类的

/**
 * 画笔
 */
private Paint mPaint;
/**
 * code的size
 */
private float mCodeTextSize;
/**
 * code的字符串
 */
private String mCodeStr;
/**
 * 字符串的长度
 */
private int mCodeLength;
/**
 * 文本矩形
 */
private Rect mRect;
/**
 * 验证码的类型
 */
private int mCodeType;
/**
 * 纯数字
 */
public final static int NUM_CODE = 0;
/**
 * 纯字母
 */
public final static int LETTER_CODE = 1;
/**
 * 汉子
 */
public final static int CHAINESE_CODE = 2;
/**
 * 数字与字母
 */
public final static int LETTER_NUM_CODE = 3;
/**
 * 点的数量,可以自己定义
 */
private int mSortNum = 100;
/**
 * 线的数量,可以自己定义
 */
private int mLineNum = 5;
private Random random = new Random();

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

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

public VerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    /**
     * 获取自定义属性
     */
    TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.custom_Verification_Code);
    mCodeTextSize = typedArray.getDimension(R.styleable.custom_Verification_Code_codeTextSize,14f);
    mCodeLength = typedArray.getInteger(R.styleable.custom_Verification_Code_codeLength,4);
    mCodeType = typedArray.getInt(R.styleable.custom_Verification_Code_codeType,0);
    typedArray.recycle();
    mCodeStr = randomText();
    initPaint();
    Log.d("custom_view",mCodeStr);
    setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View view) {
            /**
             * 点击重新生成字符串并刷新控件
             */
            mCodeStr = randomText();
            postInvalidate();
        }
    });
}

/**
 * 返回生成的字符串
 * @return
 */
public String getCodeStr() {
    return mCodeStr;
}

/**
 * 初始化画笔,并且把字符串的宽高赋值给一个矩形
 */
private void initPaint(){
    mPaint = new Paint();
    mPaint.setTextSize(mCodeTextSize);
    mRect = new Rect();
    mPaint.getTextBounds(mCodeStr,0,mCodeStr.length(),mRect);
}

/**
 * 随机生成不同类型的验证码
 * @return
 */
private String randomText() {
    StringBuilder codeSb = new StringBuilder();
    for (int i = 0; i < mCodeLength; i++) {
        switch (mCodeType){
            case NUM_CODE:
                int randomInt = (int) Math.floor(Math.random()*10);//随机数取整
                codeSb.append(randomInt);
                break;
            case LETTER_CODE:
                codeSb.append(getLetter());
                break;
            case CHAINESE_CODE:
                codeSb.append(getChineseChar());
                break;
            case LETTER_NUM_CODE:
                codeSb.append(getLetterAndNum());
                break;
        }
    }
    return codeSb.toString();
}
接着就是View大小的计算,需要重写onMeasure

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    /**
     * 设置控件的宽高
     */
    Log.d("custom_view","2");

    int width = 0;
    int height = 0;
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    if (widthMode==MeasureSpec.EXACTLY){
        /**
         * 给了具体的宽高
         */
        width = getPaddingLeft()+getPaddingRight()+widthSize;
    }else {
        /**
         * 自适应宽高
         */
        width = getPaddingLeft()+getPaddingRight()+mRect.width();
    }

    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    if (heightMode==MeasureSpec.EXACTLY){
        height = getPaddingTop()+getPaddingBottom()+heightSize;
    }else {
        height = getPaddingTop()+getPaddingBottom()+mRect.height();
    }

    setMeasuredDimension(width,height);
}
接下来是一些坐标点的计算

/**
 * 文字y轴
 * @param height
 * @return
 */
private  int getPositon(int height) {
    int strY = (int) (Math.random() * height);
    if (strY < 20) {
        strY += 20;
    }
    return strY;
}

/**
 * 随机产生原点
 * @param height
 * @param width
 * @return
 */
public static int[] getSortXY(int height, int width) {
    int[] SortXY = { 0, 0};
    SortXY[0] = (int) (Math.random() * width);
    SortXY[1] = (int) (Math.random() * height);
    return SortXY;
}

/**
 * 生成线条的起点和重点坐标
 * @param height
 * @param width
 * @return
 */
public static int[] getLineXY(int height, int width) {
    int[] lineSortXY = { 0, 0, 0, 0 };
    for (int i = 0; i < 4; i += 2) {
        lineSortXY[i] = (int) (Math.random() * width);
        lineSortXY[i + 1] = (int) (Math.random() * height);
    }
    return lineSortXY;
}
接着就是画图了,ondraw

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 画背景
         */
        mPaint.setAntiAlias(true); // 消除锯齿
        Resources resources = getResources();
        Drawable backDrawable = resources.getDrawable(R.drawable.code_back);
        if (backDrawable!=null){
            backDrawable.setBounds(0,0,getMeasuredWidth(),getMeasuredHeight());
            backDrawable.draw(canvas);
        }

        /**
         * 画点
         */
        for(int i = 0; i < mSortNum; i ++)
        {
            mPaint.setColor(Color.argb(100,random.nextInt(255),random.nextInt(255),random.nextInt(255)));
            int randomInt = random.nextInt(5);
            int [] SortXY = getSortXY(getMeasuredHeight(), getMeasuredWidth());
            canvas.drawCircle(SortXY[0], SortXY[1], randomInt, mPaint);
        }
        /**
         * 画线
         */
        for (int i = 0;i < mLineNum;i++){
            mPaint.setColor(Color.argb(100,random.nextInt(255),random.nextInt(255),random.nextInt(255)));
            int [] lineXY = getLineXY(getMeasuredHeight(),getMeasuredWidth());
            mPaint.setStrokeWidth(5);
            canvas.drawLine(lineXY[0],lineXY[1],lineXY[2],lineXY[3],mPaint);
        }


        /**
         * 画文字
         */
        for(int i = 0; i < mCodeStr.length(); i ++){
            mPaint.setColor(Color.argb(100,random.nextInt(255),random.nextInt(255),random.nextInt(255)));
            int tx = (getMeasuredWidth()-getPaddingLeft()-getPaddingRight())/(mCodeLength+1)*(i+1);
            //canvas.rotate((float) (Math.random()*10)-5);
            canvas.drawText(mCodeStr.charAt(i)+"",tx, getHeight() / 2 + getPositon(mRect.height() / 2), mPaint);
//            canvas.restore();
//            canvas.save();
        }

    }
好了,到这里这个View就算完成了,接着只需要在布局文件中加入控件就可以了

<zjt.com.customviewdemo.VerificationCodeView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:codeTextSize="20sp"
    app:codeLength="6"
    app:codeType="litterAndNum"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:paddingTop="15dp"
    android:paddingBottom="15dp"
    />

接下来是个效果图


到这里这个控件就算完成了

资源链接:

Android随机生成验证码自定义View

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值