今天编写了一个本地验证码的Demo和大家一起分享。
Demo拥有验证码的基本功能,点击切换图片,随机生成验证码,位置动态变化等,还预留了动态改变字体颜色等接口。下边贴出效果图:
实现如下:
首先自定义View实现验证码图片的绘制
package com.jacky.mydraw;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
/**
* 功能:自定义验证码实现类
* 博客:http://blog.csdn.net/u010538765/article/
* 时间:2013.8.19
* @author Jacky
*
*/
class CheckView extends View
{
//验证码图片
private Bitmap bitmap = null;
//随机生成所有的数组
final String[] strContent = new String[]{"0","1","2","3","4","5", "6", "7", "8", "9"};
//构造函数
public CheckView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void draw(Canvas canvas)
{
Paint paint = new Paint();
if (bitmap != null) {
canvas.drawBitmap(bitmap, 0, 0, paint);
} else {
paint.setColor(Color.GRAY);
paint.setTextSize(20);
canvas.drawText("点击换一换", 10, 30, paint);
}
super.draw(canvas);
}
/**
* 得到验证码;设置图片
* @return 生成的验证码中的数字
*/
public String[] getValidataAndSetImage() {
//产生随机数
String [] strRes = generageRadom(strContent);
//传随机串和随机数
bitmap = generateValidate(strContent,strRes);
//刷新
invalidate();
return strRes;
}
/**
* 绘制验证码并返回
* @param strContent
* @param strRes
* @return
*/
private Bitmap generateValidate(String[] strContent,String [] strRes) {
int width = 120,height = 57;
int isRes = isStrContent(strContent);
if (isRes == 0) {
return null;
}
//创建图片和画布
Bitmap sourceBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
Canvas canvas = new Canvas(sourceBitmap);
canvas.drawColor(Color.YELLOW);
Paint numPaint = new Paint();
numPaint.setTextSize(40);
numPaint.setFakeBoldText(true);
numPaint.setColor(Color.BLACK);
//设置每个字
canvas.drawText(strRes[0], 10, height * 3 / 4, numPaint);
Matrix mMatrix = new Matrix();
mMatrix.setRotate((float)Math.random()*25);
canvas.setMatrix(mMatrix);
canvas.drawText(strRes[1], 40, height * 3 / 4, numPaint);
mMatrix.setRotate((float)Math.random()*25);
canvas.setMatrix(mMatrix);
canvas.drawText(strRes[2], 70, height * 3 / 4 - 10, numPaint);
mMatrix.setRotate((float)Math.random()*25);
canvas.setMatrix(mMatrix);
canvas.drawText(strRes[3], 100, height * 3 / 4 - 15, numPaint);
mMatrix.setRotate((float)Math.random()*25);
canvas.setMatrix(mMatrix);
//设置绘制干扰的画笔
Paint interferencePaint = new Paint();
interferencePaint.setAntiAlias(true);
interferencePaint.setStrokeWidth(4);
interferencePaint.setColor(Color.BLACK);
interferencePaint.setStyle(Paint.Style.FILL); //设置paint的style
//绘制直线
int [] line;
for(int i = 0; i < 2; i ++)
{
line = CheckGetUtil.getLine(height, width);
canvas.drawLine(line[0], line[1], line[2], line[3],interferencePaint);
}
// 绘制小圆点
int [] point;
for(int i = 0; i < 100; i++)
{
point=CheckGetUtil.getPoint(height, width);
canvas.drawCircle(point[0], point[1], 1, interferencePaint);
}
canvas.save();
return sourceBitmap;
}
private int isStrContent(String[] strContent) {
if (strContent == null || strContent.length <= 0) {
return 0;
} else {
return 1;
}
}
/**
* 从指定数组中随机取出4个字符(数组)
* @param strContent
* @return
*/
private String[] generageRadom(String[] strContent){
String[] str = new String[4];
// 随机串的个数
int count = strContent.length;
// 生成4个随机数
Random random = new Random();
int randomResFirst = random.nextInt(count);
int randomResSecond = random.nextInt(count);
int randomResThird = random.nextInt(count);
int randomResFourth = random.nextInt(count);
str[0] = strContent[randomResFirst].toString().trim();
str[1] = strContent[randomResSecond].toString().trim();
str[2] = strContent[randomResThird].toString().trim();
str[3] = strContent[randomResFourth].toString().trim();
return str;
}
/**
* 从指定数组中随机取出4个字符(字符串)
* @param strContent
* @return
*/
private String generageRadomStr(String[] strContent){
StringBuilder str = new StringBuilder();
// 随机串的个数
int count = strContent.length;
// 生成4个随机数
Random random = new Random();
int randomResFirst = random.nextInt(count);
int randomResSecond = random.nextInt(count);
int randomResThird = random.nextInt(count);
int randomResFourth = random.nextInt(count);
str.append(strContent[randomResFirst].toString().trim());
str.append(strContent[randomResSecond].toString().trim());
str.append(strContent[randomResThird].toString().trim());
str.append(strContent[randomResFourth].toString().trim());
return str.toString();
}
/**
* 给定范围获得随机颜色,未使用
*
* @param rc
* 0-255
* @param gc
* 0-255
* @param bc
* 0-255
* @return colorValue 颜色值,使用setColor(colorValue)
*/
public int getRandColor(int rc, int gc, int bc) {
Random random = new Random();
if (rc > 255)
rc = 255;
if (gc > 255)
gc = 255;
if (bc > 255)
bc = 255;
int r = rc + random.nextInt(rc);
int g = gc + random.nextInt(gc);
int b = bc + random.nextInt(bc);
return Color.rgb(r, g, b);
}
}
随后在XML文件中添加自定义View:
<com.jacky.mydraw.CheckView
android:id="@+id/checkView"
android:layout_width="80sp"
android:layout_height="38sp"
android:layout_marginLeft="5dp" >
</com.jacky.mydraw.CheckView>
编写工具类,随机生成线和点的位置,验证验证码,生成随机数等均可在此类中进行。
package com.jacky.mydraw;
/**
* 功能:验证码相关工具类
* 博客:http://blog.csdn.net/u010538765/article/
* 时间:2013.8.19
* @author Jacky
* */
public class CheckGetUtil
{
//获得画干扰直线的位置
public static int[] getLine(int height, int width)
{
int [] tempCheckNum = {0, 0 ,0, 0, 0};
for(int i = 0; i < 4; i+=2)
{
tempCheckNum[i] = (int) (Math.random() * width);
tempCheckNum[i + 1] = (int) (Math.random() * height);
}
return tempCheckNum;
}
//获得干扰点的位置
public static int[] getPoint(int height, int width)
{
int [] tempCheckNum = {0, 0, 0, 0, 0};
tempCheckNum[0] = (int) (Math.random() * width);
tempCheckNum[1] = (int) (Math.random() * height);
return tempCheckNum;
}
}
最后,调用实现
package com.jacky.mydraw;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
public class CheckActivity extends Activity
{
private CheckView mMyView = null;
private String[] res = new String[4]; //获取每次更新的验证码,可用于判断用户输入是否正确
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_check);
mMyView = (CheckView)findViewById(R.id.checkView);
//初始化验证码
res = mMyView.getValidataAndSetImage();
mMyView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//重新初始化验证码
res = mMyView.getValidataAndSetImage();
}
});
}
}
该Demo实现了简单的验证码功能,可以根据需要自行修改。
最后,在编写过程中注意到android单位的问题。下边总结常用单位,相信看过下边的分析后以后就不会对sp,sp,px等陌生了。
1. px(“pixel”即像素):不推荐使用,用该单位设定的大小在不同分辨率的手机上展现的实际大小有可能不同
2. dp:它与“像素密度”密切相关,所以首先我们解释一下什么是像素密度。假设有一部手机,屏幕的物理尺寸为1.5英寸x2英寸,屏幕分辨率为240x320,则我们可以计算出在这部手机的屏幕上,每英寸包含的像素点的数量为240/1.5=160dpi(横向)或320/2=160dpi(纵向),160dpi就是这部手机的像素密度,像素密度的单位dpi是Dots Per Inch的缩写,即每英寸像素数量。横向和纵向的这个值都是相同的,原因是大部分手机屏幕使用正方形的像素点。Android系统定义了四种像素密度:低(120dpi)、中(160dpi)、高(240dpi)和超高(320dpi),它们对应的dp到px的系数分别为0.75、1、1.5和2,这个系数乘以dp长度就是像素数。用该单位设定的大小在不同手机上显示的物理尺寸“差不多”。
3. dpi(“Dots Per Inch”即像素密度):dp完全相同,只是名字不同而已。在早期的Android版本里多使用dip,后来为了与sp统一就建议使用dp这个名字了。
4. sp:(“Scale-independent Pixel”即与缩放无关的抽象像素):sp和dp很类似但唯一的区别是,Android系统允许用户自定义文字尺寸大小(小、正常、大、超大等等),当文字尺寸是“正常”时1sp=1dp=0.00625英寸,而当文字尺寸是“大”或“超大”时,1sp>1dp=0.00625英寸。类似我们在windows里调整字体尺寸以后的效果——窗口大小不变,只有文字大小改变。
注:Google建议文本用sp,其他用dp(dip)。
其他一些不常用的单位:
5.pt: point(磅),是一个标准的长度单位,1pt=1/72英寸,用于印刷业,非常简单易用。
6.in(英寸):长度单位。
7.mm(毫米):长度单位。
最后附上Demo的下载地址:http://download.csdn.net/detail/u010538765/5976773