运行效果
产生原理
自定义一组字符数组,随机在里面挑选出自己想要产生的验证码个数的字符,用画笔画入自己定义的BitMap中,然后在随机画入干扰线条,当然绘制时的一些参数都是随机产生的,比如:颜色,字体格式,字体之间的间隔,线条的格式等等都是随机的,下面来看看具体的实现步骤;
具体过程
定义一组字符数组
定义一组字符数组,用于随机产生我们想要的字符,然后绘制成验证码
/**
* 所有产生验证码的字符
*/
private static 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'
};
随机生成字符
随机生成几个字符,字符的数量CODE_LENGTH是我们自己传入的,具体:
/**
* 随机得到验证码要显示的字符,个数为我们自己设置
* @return 得到一个字符串
*/
private String createCode() {
StringBuilder buffer = new StringBuilder();
//根据传入验证码的长度来随机生成数组里面的字符
for (int i = 0; i < CODE_LENGTH; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
创造画布
既然是要绘制验证码,比不可少的一个就是画布Canvars了,先创建一个验证码要显示的BitMap,然后把BitMap变成画布,
画布的颜色是自己设置的
//创建一个用来 显示验证码的BitMap
Bitmap bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Config.ARGB_8888);
//实例化一个画布对象,将bitmap传入
Canvas canvas = new Canvas(bitmap);
//画布颜色
canvas.drawColor(Color.rgb(DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_COLOR));
创建画笔
画笔也是绘制必不可少的一个
//实例化画笔对象
Paint paint = new Paint();
//设置绘制字体的大小
paint.setTextSize(FONT_SIZE);
设置要绘制的字体的格式
/**
* 设置验证码的字体格式
* @param paint
*/
private void randomTextStyle(Paint paint) {
int color = randomColor(1);
paint.setColor(color);
paint.setFakeBoldText(random.nextBoolean()); //true为粗体,false为非粗体
float skewX = random.nextInt(11) / 10;
skewX = random.nextBoolean() ? skewX : -skewX;
paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
// paint.setUnderlineText(true); //true为下划线,false为非下划线
// paint.setStrikeThruText(true); //true为删除线,false为非删除线
}
设置颜色
/**
* 设置验证码的颜色
*/
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);
}
验证码的位置
canvers.drawText()方法需要4个参数,要绘制的文本,X坐标,Y坐标,画笔,现在我们已经有要绘制的文本了(就是随机产生的字符),画笔Paint,还差两个参数
/**
* 随机产生验证码之间的间隔
*/
private void randomPadding() {
padding_left += BASE_PADDING_LEFT + random.nextInt(RANGE_PADDING_LEFT);
padding_top = BASE_PADDING_TOP + random.nextInt(RANGE_PADDING_TOP);
}
绘制验证码
/*
开始将字符串绘制成验证码
参数1:要绘制的文本,参数2,3:X,Y坐标,参数3:画笔
*/
canvas.drawText(code.charAt(i) + "", padding_left, padding_top, paint);
参数是怎么随机产生的呢:
//根据字符串长度来绘制验证码
for (int i = 0; i < code.length(); i++) {
randomTextStyle(paint);//调用方法随机生成画笔的格式
randomPadding();//调用方法产生随机的边距
/*
开始将字符串绘制成验证码
参数1:要绘制的文本,参数2,3:X,Y坐标,参数3:画笔
*/
canvas.drawText(code.charAt(i) + "", padding_left, padding_top, paint);
}
以上就是绘制验证码的方法了,下面绘制干扰线
绘制干扰线
/**
* 画干扰线
* @param canvas
* @param paint
*/
private void drawLine(Canvas canvas, Paint paint) {
int color = randomColor(1);
int startX = random.nextInt(DEFAULT_WIDTH);
int startY = random.nextInt(DEFAULT_HEIGHT);
int stopX = random.nextInt(DEFAULT_WIDTH);
int stopY = random.nextInt(DEFAULT_HEIGHT);
paint.setStrokeWidth(1);//设置线宽
paint.setColor(color);//设置字体颜色
canvas.drawLine(startX, startY, stopX, stopY, paint);//绘制线条
}
//根据传入的线条数画线条
for (int i = 0; i < LINE_NUMBER; i++) {
drawLine(canvas, paint);
}
返回验证码的方法
创建一个返回验证码的方法,用于比较用户输入的的验证码是否正确
/**
* 得到验证码的方法,用于验证输入的对不对
*/
public String getCode() {
return code.toLowerCase();
}
demo的具体实现
绘制验证码类
package com.duanlian.verificationcodedemo;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Bitmap.Config;
public class VerificationCode {
/*
验证码的长度和多少条干扰线都是通过调用他的类传入的
*/
private static int CODE_LENGTH;//验证码的长度
private static int LINE_NUMBER;//多少条干扰线
private static final int FONT_SIZE = 60;//字体大小
private static final int BASE_PADDING_LEFT = 20; //左边距
private static final int RANGE_PADDING_LEFT = 35;//左边距范围值
private static final int BASE_PADDING_TOP = 42;//上边距
private static final int RANGE_PADDING_TOP = 15;//上边距范围值
private static final int DEFAULT_WIDTH = 300;//默认宽度.图片的总宽,当验证码过多时,默认宽度要改大
private static final int DEFAULT_HEIGHT = 70;//默认高度.图片的总高
private final int DEFAULT_COLOR = 0xdf;//默认背景颜色值
private String code;//保存生成的验证码
private int padding_left, padding_top;
private Random random = new Random();
/**
* 所有产生验证码的字符
*/
private static 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 static VerificationCode bpUtil;
private VerificationCode() {
}
//调用的时候传入验证码的长度和干扰线的多少
public static VerificationCode getInstance(int codeLen, int lineNum) {
VerificationCode.CODE_LENGTH = codeLen;
VerificationCode.LINE_NUMBER = lineNum;
if (bpUtil == null)
bpUtil = new VerificationCode();
return bpUtil;
}
/**
* 创建一个公有的方法用于返回创建的bitmap
*/
public Bitmap getBitmap() {
return createBitmap();
}
/**
* 创造一个bitmap
*/
private Bitmap createBitmap() {
padding_left = 0;
//创建一个用来 显示验证码的BitMap
Bitmap bitmap = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Config.ARGB_8888);
//实例化一个画布对象,将bitmap传入
Canvas canvas = new Canvas(bitmap);
//画布颜色
canvas.drawColor(Color.rgb(DEFAULT_COLOR, DEFAULT_COLOR, DEFAULT_COLOR));
//调用随机得到验证码要显示的字符方法,得到要画到画布上的字符串
code = createCode();
//实例化画笔对象
Paint paint = new Paint();
//设置绘制字体的大小
paint.setTextSize(FONT_SIZE);
//根据字符串长度来绘制验证码
for (int i = 0; i < code.length(); i++) {
randomTextStyle(paint);//调用方法随机生成画笔的格式
randomPadding();//调用方法产生随机的边距
/*
开始将字符串绘制成验证码
参数1:要绘制的文本,参数2,3:X,Y坐标,参数3:画笔
*/
canvas.drawText(code.charAt(i) + "", padding_left, padding_top, paint);
}
//根据传入的线条数画线条
for (int i = 0; i < LINE_NUMBER; i++) {
drawLine(canvas, paint);
}
canvas.save(Canvas.ALL_SAVE_FLAG);//保存
canvas.restore();
return bitmap;
}
/**
* 得到验证码的方法,用于验证输入的对不对
*
* @return
*/
public String getCode() {
return code.toLowerCase();
}
/**
* 随机得到验证码要显示的字符,个数为我们自己设置
* @return 得到一个字符串
*/
private String createCode() {
StringBuilder buffer = new StringBuilder();
//根据传入验证码的长度来随机生成数组里面的字符
for (int i = 0; i < CODE_LENGTH; i++) {
buffer.append(CHARS[random.nextInt(CHARS.length)]);
}
return buffer.toString();
}
/**
* 画干扰线
* @param canvas
* @param paint
*/
private void drawLine(Canvas canvas, Paint paint) {
int color = randomColor(1);
int startX = random.nextInt(DEFAULT_WIDTH);
int startY = random.nextInt(DEFAULT_HEIGHT);
int stopX = random.nextInt(DEFAULT_WIDTH);
int stopY = random.nextInt(DEFAULT_HEIGHT);
paint.setStrokeWidth(1);//设置线宽
paint.setColor(color);//设置字体颜色
canvas.drawLine(startX, startY, stopX, stopY, paint);//绘制线条
}
/**
* 设置验证码的颜色
*/
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);
}
/**
* 设置验证码的字体格式
* @param paint
*/
private void randomTextStyle(Paint paint) {
int color = randomColor(1);
paint.setColor(color);
paint.setFakeBoldText(random.nextBoolean()); //true为粗体,false为非粗体
float skewX = random.nextInt(11) / 10;
skewX = random.nextBoolean() ? skewX : -skewX;
paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
// paint.setUnderlineText(true); //true为下划线,false为非下划线
// paint.setStrikeThruText(true); //true为删除线,false为非删除线
}
/**
* 随机产生验证码之间的间隔
*/
private void randomPadding() {
padding_left += BASE_PADDING_LEFT + random.nextInt(RANGE_PADDING_LEFT);
padding_top = BASE_PADDING_TOP + random.nextInt(RANGE_PADDING_TOP);
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.duanlian.verificationcodedemo.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textSize="25sp"
android:gravity="center"
android:text="验证码"/>
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="请输入验证码"/>
<EditText
android:id="@+id/edittext"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:onClick="virification"
android:text="验证"/>
</LinearLayout>
Activity具体逻辑
package com.duanlian.verificationcodedemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private ImageView imageView;
private VerificationCode code;
private String verificationCode;
private EditText editText;
private String inputCode;
String TAG = "duanlian====";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
imageView = (ImageView) findViewById(R.id.image);
editText = (EditText) findViewById(R.id.edittext);
inputCode = editText.getText().toString().trim();//拿到用户输入的验证码
Log.w(TAG,"inputCode"+inputCode);
//调用方法拿到对象,传入2个参数,参数1:要绘制的验证码个数,参数2:要绘制的干扰线条的条数
code = VerificationCode.getInstance(5,4);
imageView.setImageBitmap(code.getBitmap());
verificationCode = code.getCode();//拿到验证码
//点击imageView后刷新验证码
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
imageView.setImageBitmap(code.getBitmap());
verificationCode = code.getCode();//拿到刷新之后的验证码
Log.w(TAG,"verificationCode==="+verificationCode);
}
});
}
/**
* 验证按钮的监听
*/
public void virification(View view){
inputCode = editText.getText().toString().trim();//拿到用户输入的验证码
Log.w(TAG,"inputCode"+inputCode);
if (verificationCode.equals(inputCode)) {
Toast.makeText(MainActivity.this, "验证成功", Toast.LENGTH_SHORT).show();
} else if (TextUtils.isEmpty(inputCode)) {
Toast.makeText(MainActivity.this, "请输入验证码", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "您输入的验证码有误", Toast.LENGTH_SHORT).show();
}
}
}