暑假的班级项目登录界面用到了验证码,就想着简单点弄个图片验证码好了。看了几篇文章还是有点儿懵。然后耐着性子把一篇关于验证码的文章分析了一下。果然还是得有耐心才行啊。 ╰( ̄ω ̄o)
虽然大致是做出来了,但是还有个小bug,就是文字会出界的问题,如果有更好的解决方案的,欢迎提出呀!(~o ̄3 ̄)
大概是参照这篇博客的:https://blog.csdn.net/wk843620202/article/details/50960904
先上效果图
然后,我们先从布局文件开始
因为主要是看验证码,布局部分我就只截取那一行的代码了
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="20dp"
android:layout_gravity="center_horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left">
<EditText
android:id="@+id/identifyingcode_edittext"
android:layout_width="100dp"
android:layout_height="match_parent"
android:hint="验证码"
android:maxLength="4"
android:textColor="#4e4e4e"
android:textSize="20sp" />
</LinearLayout>
<!--这里预留一个ImageView来放图形验证码-->
<ImageView
android:id="@+id/identifyingcode_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
/>
</LinearLayout>
接下来就是一个专门产生图形验证码的类了。首先我们新建一个类(在这里我取名IdentifyingCode)
package util;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import java.util.Random;
/**
* @author jiaru
* 这个类用来生成验证码
*/
public class IdentifyingCode {
//随机数数组,验证码上的数字和字母
private static final char[] CHARS={
'0','1','2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm',
'n', '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', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
};
//这是一个单例模式
private static IdentifyingCode IdentifyingCode;
public static IdentifyingCode getInstance(){
if(IdentifyingCode==null){
IdentifyingCode=new IdentifyingCode();
}
return IdentifyingCode;
}
//验证码个数
private static final int CODE_LENGTH = 4;
//字体大小
private static final int FONT_SIZE = 50;
//线条数
private static final int LINE_NUMBER = 5;
//padding,其中base的意思是初始值,而range是变化范围。数值根据自己想要的大小来设置
private static final int BASE_PADDING_LEFT=10,RANGE_PADDING_LEFT=100,BASE_PADDING_TOP=75,RANGE_PADDING_TOP=50;
//验证码默认宽高
private static final int DEFAULT_WIDTH=400,DEFAULT_HEIGHT=150;
//画布的长宽
private int width=DEFAULT_WIDTH,height=DEFAULT_HEIGHT;
//字体的随机位置
private int base_padding_left=BASE_PADDING_LEFT,range_padding_left=RANGE_PADDING_LEFT,
base_padding_top=BASE_PADDING_TOP,range_padding_top=RANGE_PADDING_TOP;
//验证码个数,线条数,字体大小
private int codeLength=CODE_LENGTH,line_number=LINE_NUMBER,font_size=FONT_SIZE;
private String code;
private int padding_left,padding_top;
private Random random=new Random();
//验证码图片(生成一个用位图)
public Bitmap createBitmap(){
padding_left=0;
padding_top=0;
//创建指定格式,大小的位图//Config.ARGB_8888是一种色彩的存储方法
Bitmap bp=Bitmap.createBitmap(width,height, Bitmap.Config.ARGB_8888);
Canvas c=new Canvas(bp);
code =createCode();
//将画布填充为白色
c.drawColor(Color.WHITE);
//新建一个画笔
Paint paint =new Paint();
//设置画笔抗锯齿
paint.setAntiAlias(true);
paint.setTextSize(font_size);
//在画布上画上验证码
// Paint.FontMetrics fontMetrics = paint.getFontMetrics();
for(int i=0;i<code.length();i++){
randomTextStyle(paint);
randomPadding();
//这里的padding_left,padding_top是文字的基线
c.drawText(code.charAt(i)+"",padding_left,padding_top,paint);
}
//画干扰线
for(int i = 0;i<line_number;i++){
drawLine(c,paint);
}
//保存一下画布
c.save();
c.restore();
return bp;
}
//生成验证码
private String createCode(){
StringBuilder sb=new StringBuilder();
//利用random生成随机下标
for(int i=0;i<codeLength;i++){
sb.append(CHARS[random.nextInt(CHARS.length)]);
}
return sb.toString();
}
//画线
private void drawLine(Canvas canvas,Paint paint){
int color=randomColor();
int startX=random.nextInt(width);
int startY=random.nextInt(height);
int stopX=random.nextInt(width);
int stopY=random.nextInt(height);
paint.setStrokeWidth(1);
paint.setColor(color);
canvas.drawLine(startX,startY,stopX,stopY,paint);
}
//随机文字样式,颜色,文字粗细与倾斜度
private void randomTextStyle(Paint paint){
int color=randomColor();
paint.setColor(color);
paint.setFakeBoldText(random.nextBoolean());//true为粗体,false为非粗体
double skew =random.nextInt(11)/10;
//随机ture或者false来生成正数或者负数,来表示文字的倾斜度,负数右倾,正数左倾
skew=random.nextBoolean()?skew:-skew;
// paint.setUnderlineText(true);//下划线
// paint.setStrikeThruText(true);//删除线
}
//生成随机颜色,利用RGB
private int randomColor(){
return randomColor(1);
}
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);
}
//验证码位置随机
private void randomPadding(){
padding_left+=base_padding_left+random.nextInt(range_padding_left);
padding_top=base_padding_top+random.nextInt(range_padding_top);
}
public String getCode(){
return code;
}
}
大致的内容我都在注释里讲了。这个生成验证码,主要是将一个位图放在ImageView中,然后用画布将验证码以及干扰线画上去,你也可以设置下划线或者删除线。
然后一开始我发现,我点了几次验证码后,验证码图片会出现,没有了文字的情况,考虑到应该是文字出界了。因为Canvas画文字有基线的,因此,我们只要保证验证码的中心坐标,是依次从左到右,而每个字的y坐标不定,就可以做出,文字在上蹿下跳的效果。
因此作为基线的padding_left,是从base_padding_left依次增加的。而每次增加的幅度,由random随机产生。最大幅度由range_padding_left控制。
而padding_top,因为是可以上上下下,但是,注意不能出界。所以不是padding_top+=base_padding_top+幅度,而是=;也就是说,从左到右,不是依次往下降的,而是上蹿下跳的。这样只要控制base_padding_top和range_padding_top就不会出界了。(其实有更准确的方法的,但是我没有深究下去,文末会附上参考博客,有兴趣的同学研究一下咯)
好,那么,接下来就是怎么用这个类啦!
其实只需要,在activity中,定义一个ImageView对象,然后绑定布局中的ImageView,就可以调用IdentifyingCode中的方法来创建一个验证码啦。
然后给这个ImageView设一个监听,就可以点击这个验证码就换一次图片啦!
private ImageView identifyingCode;
//这里是初始化并设置监听,记得要保存对的验证码,用来验证后面用户输入的对不对
identifyingCode=(ImageView)findViewById(R.id.identifyingcode_image);
identifyingCode.setOnClickListener(this);
identifyingCode.setImageBitmap(IdentifyingCode.getInstance().createBitmap());
realCode=IdentifyingCode.getInstance().getCode().toLowerCase();
然后在OnClick那里,再来这两个语句,就做到可以刷新验证码了。( ̄︶ ̄)↗
identifyingCode.setImageBitmap(IdentifyingCode.getInstance().createBitmap());
realCode=IdentifyingCode.getInstance().getCode().toLowerCase();
就这样,一个五颜六色的验证码,就完成了。
参考博客:
- android随机生成验证码https://blog.csdn.net/wk843620202/article/details/50960904
- bitMap的介绍以及他与Canvas的关联https://www.cnblogs.com/jenson138/p/4302073.html
- Canvas的介绍https://www.cnblogs.com/huolongluo/p/5797766.html
- 画笔Paint的介绍以及他与Canvas的联系https://blog.csdn.net/sinat_35762047/article/details/54965298#一paint和canvas
- 里面出现到的Config又是什么呢?https://blog.csdn.net/u010885095/article/details/44938875
- 在Canvas上画文字,这里有涉及文字出界内容https://blog.csdn.net/osle123/article/details/52756696
- 关于Canvas的drawTexthttps://blog.csdn.net/zly921112/article/details/50401976