1. 前言

图形验证码可以让服务器以图片的形式传给客户端,也可以让客户端自己实现。那客户端要怎么做呢?其实很简单,可以使用Android的Canvas、Paint和Random来实现。用Random来随机生成数字、字母、颜色、画笔原点等等,设置Paint的颜色和样式,然后再Canvas上面绘制,这样一个图形验证码就生成好了。

2. 具体实现

根据上面所说的,我们可以封装一个工具类来使用,详细功能有:

  • 自定义验证码类型:数字、字母、数字字母组合
  • 自定义验证码大小
  • 自定义验证码背景颜色
  • 自定义干扰线数量
  • 自定义字体大小、数量、间距

具体代码如下:

package com.fantasy.blogdemo.captcha;import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;import java.util.Random;/*** 图形验证码工具* <pre>*     author  : Fantasy*     version : 1.0, 2019-06-27*     since   : 1.0, 2019-06-27* </pre>*/
public class Captcha {private static final char[] CHARS_NUMBER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};private static final char[] CHARS_LETTER = {'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 final char[] CHARS_ALL = {'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 int mWidth;/*** 验证码图片的高度*/private int mHeight;private int mBackgroundColor;/*** 验证码的长度*/private int mLength;/*** 干扰线的数量*/private int mLineNumber;private int mFontSize;/*** 字体左边距*/private int mFontPaddingLeft;/*** 字体左边距范围值*/private int mFontPaddingLeftRang;/*** 字体上边距*/private int mFontPaddingTop;/*** 字体上边距范围值*/private int mFontPaddingTopRang;private TYPE mType;private Random mRandom;private static Captcha mInstance;/*** 生成的验证码*/private String mCode;public enum TYPE {NUMBER, LETTER, CHARS}private Captcha() {mType = TYPE.CHARS;mWidth = 200;mHeight = 80;mBackgroundColor = Color.WHITE;mLength = 4;mLineNumber = 2;mFontSize = 50;mFontPaddingLeft = 20;mFontPaddingLeftRang = 20;mFontPaddingTop = 45;mFontPaddingTopRang = 15;mRandom = new Random();}public static Captcha getInstance() {if (mInstance == null) {synchronized (Captcha.class) {mInstance = new Captcha();}}return mInstance;}/*** 设置验证码类型,有:数字、英文字母、数字加英文字母** @param type 类型* @return CaptchaUtils实例*/public Captcha setType(TYPE type) {mType = type;return mInstance;}/*** 设置验证码图片大小** @param width  宽度* @param height 高度* @return CaptchaUtils实例*/public Captcha setSize(int width, int height) {mWidth = width;mHeight = height;return mInstance;}/*** 设置背景颜色** @param color 颜色* @return CaptchaUtils实例*/public Captcha setBackgroundColor(int color) {mBackgroundColor = color;return mInstance;}/*** 设置验证码的长度** @param length 长度* @return CaptchaUtils实例*/public Captcha setLength(int length) {mLength = length;return mInstance;}/*** 设置干扰性数量** @param number 数量* @return CaptchaUtils实例*/public Captcha setLineNumber(int number) {mLineNumber = number;return mInstance;}/*** 设置字体大小** @param size 字体大小* @return CaptchaUtils实例*/public Captcha setFontSize(int size) {mFontSize = size;return mInstance;}/*** 设置字体间距** @param paddingLeft 左边距* @param paddingTop  上边距* @return CaptchaUtils实例*/public Captcha setFontPadding(int paddingLeft, int paddingTop) {mFontPaddingLeft = paddingLeft;mFontPaddingTop = paddingTop;return mInstance;}/*** 设置字体间距** @param paddingLeft     左边距* @param paddingLeftRang 左边距范围值* @param paddingTop      上边距* @param paddingTopRang  上边距范围值* @return CaptchaUtils实例*/public Captcha setFontPadding(int paddingLeft, int paddingLeftRang, int paddingTop,int paddingTopRang) {mFontPaddingLeft = paddingLeft;mFontPaddingLeftRang = paddingLeftRang;mFontPaddingTop = paddingTop;mFontPaddingTopRang = paddingTopRang;return mInstance;}/*** 获取生成的图形验证码** @return 图形验证码的字符串*/public String getCode() {return mCode;}/*** 生成图形验证码** @return 图形验证码的图片*/public Bitmap create() {mCode = createCode();Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(bitmap);canvas.drawColor(mBackgroundColor);Paint paint = new Paint();paint.setTextSize(mFontSize);int fontPaddingLeft = 0;for (int i = 0; i < mCode.length(); i++) {getRandomTextStyle(paint);fontPaddingLeft += getRandomFontPaddingLeft();canvas.drawText(String.valueOf(mCode.charAt(i)), fontPaddingLeft, getRandomFontPaddingTop(), paint);}for (int i = 0; i < mLineNumber; i++) {drawLine(canvas, paint);}canvas.save();canvas.restore();return bitmap;}/*** 生成图形验证码** @return 图形验证码的字符串*/private String createCode() {StringBuilder buffer = new StringBuilder();switch (mType) {case NUMBER:for (int i = 0; i < mLength; i++) {buffer.append(CHARS_NUMBER[mRandom.nextInt(CHARS_NUMBER.length)]);}break;case LETTER:for (int i = 0; i < mLength; i++) {buffer.append(CHARS_LETTER[mRandom.nextInt(CHARS_LETTER.length)]);}break;case CHARS:for (int i = 0; i < mLength; i++) {buffer.append(CHARS_ALL[mRandom.nextInt(CHARS_ALL.length)]);}break;default:for (int i = 0; i < mLength; i++) {buffer.append(CHARS_ALL[mRandom.nextInt(CHARS_ALL.length)]);}break;}return buffer.toString();}/*** 获取随机颜色** @return 颜色*/private int getRandomColor() {int red = mRandom.nextInt(256);int green = mRandom.nextInt(256);int blue = mRandom.nextInt(256);return Color.rgb(red, green, blue);}/*** 获取随机文本样式** @param paint 涂料*/private void getRandomTextStyle(Paint paint) {int color = getRandomColor();paint.setColor(color);paint.setFakeBoldText(mRandom.nextBoolean()); // true为粗体,false为非粗体int skewX = mRandom.nextInt(11) / 10;skewX = mRandom.nextBoolean() ? skewX : -skewX;paint.setTextSkewX(skewX); // 负数表示右斜,整数左斜// paint.setUnderlineText(true); // true为下划线,false为非下划线// paint.setStrikeThruText(true); // true为删除线,false为非删除线}/*** 获取随机字体左边距** @return 左边距*/private int getRandomFontPaddingLeft() {return mFontPaddingLeft + mRandom.nextInt(mFontPaddingLeftRang);}/*** 获取随机字体上边距** @return 上边距*/private int getRandomFontPaddingTop() {return mFontPaddingTop + mRandom.nextInt(mFontPaddingTopRang);}/*** 生成干扰性** @param canvas 画布* @param paint  涂料*/private void drawLine(Canvas canvas, Paint paint) {int color = getRandomColor();int startX = mRandom.nextInt(mWidth);int startY = mRandom.nextInt(mHeight);int stopX = mRandom.nextInt(mWidth);int stopY = mRandom.nextInt(mHeight);paint.setStrokeWidth(1);paint.setColor(color);canvas.drawLine(startX, startY, stopX, stopY, paint);}}

3. 使用方式

获取实例并设置

mCaptcha = Captcha.getInstance().setType(Captcha.TYPE.CHARS).setSize(200, 80).setBackgroundColor(Color.WHITE).setLength(4).setLineNumber(2).setFontSize(50).setFontPadding(20, 20, 45, 15);

生成图形验证码,并且在ImageView中显示

mIvCaptcha.setImageBitmap(mCaptcha.create());

获取验证码的字符串,可用于比对输入是否正确

if (result.equals(mCaptcha.getCode())) {showToast(R.string.captcha_correct);
} else {showToast(R.string.captcha_wrong);
}

4. 效果图

想看完整代码可以到我的GitHub上面看看BlogDemo。

如果想进一步交流和学习的同学,可以加一下QQ群哦!

Android图形验证码相关推荐

  1. Android图形验证码工具类

    移动端获取图形验证码有两种形式,一种是在本地随机生成进行验证,另一种是根据服务端返回的图片流设置到页面上,今天我们要做的就是根据服务端返回的操作图形验证码,完整demo地址:https://downl ...

  2. android请求动态验证码,androidstudio实现图形验证码

    androidstudio实现图形验证码 xml文件: android:layout_width="match_parent" android:layout_height=&quo ...

  3. Django博客系统注册(图形验证码接口设计和定义)

    1. 准备captcha包(该包用于生成图形验证码) 1.将生成图片验证码的库复制到新建的libs包中. 2.安装Python处理图片的库 这儿可能会变红显示错误: 解决方案:在虚拟环境中安装Pill ...

  4. 美多商城之验证码(图形验证码)

    一.图形验证码 1.1 图形验证码逻辑分析 需要新建应用verifications 知识要点 将图形验证码的文字信息保存到Redis数据库,为短信验证码做准备. UUID 用于唯一区分该图形验证码属于 ...

  5. 4.Spring Security 添加图形验证码

    添加验证码大致可以分为三个步骤:根据随机数生成验证码图片:将验证码图片显示到登录页面:认证流程中加入验证码校验.Spring Security的认证校验是由UsernamePasswordAuthen ...

  6. Python模拟登录,Python识别图形验证码实现自动登陆

    前言 利用Python识别图形验证码,selenium模块实现自动登陆.废话不多说. 让我们愉快地开始吧~ 开发工具 Python版本: 3.6.4 相关模块: re: numpy模块: pytess ...

  7. 前端 验证码隐藏怎么实现_完成图形验证码

    使用 svg-captcha 这个包并结合后端实现图形验证码功能. 基本使用 在我们项目中安装 svg-captcha 包. $ npm install svg-captcha --save 官方文档 ...

  8. java验证码局部刷新_JS局部刷新图形验证码

    开发过程当中,网络安全采取的方法之一,采用验证码功能.一般在注册.登录的程序当中见得比较多.其自己在实现这一功能时,静态页面有一段调用图形验证码的PHP文件,//,验证码是随机生成的,一般将生成的验证 ...

  9. 图形验证码最佳攻略2

    下面是注册 如果是手机用户注册,需要发送短信验证码  说明: 发送图形验证码是为了拦截发送短信的.但是不拦截"注册帐号" 但是,用户体验很别扭,因为图形验证码很显然是错误的,但是却 ...

最新文章

  1. 慢动作频闪怎么解决_Vlog的视频解决方案——索尼A6400
  2. 为什么要用OKR?OKR在什么情况下用?
  3. 20159208 《网络攻防实践》第七周学习总结
  4. 数据单位:bit、Byte、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB、、、
  5. linux crm高可用网卡,Linux运维——pacemaker实现高可用-Go语言中文社区
  6. step1 . day4 C语言基础练习之日历
  7. 实验八——函数定义及调用总结
  8. php获得指定目录文件,PHP遍历指定文件夹获取路径及大小(包含子文件夹)
  9. jggrid使用multiselect时修改默认排序
  10. 单目视觉里程计 mono vo
  11. JVM中8种垃圾收集器小结
  12. 2022年计算机专业程序员笔记本电脑推荐
  13. ServletResponse的常用方法:getWriter,setContentType
  14. JavaScript 设计模式之-单例模式(Singleton Pattern)
  15. 网站seo优化方式途径
  16. 自恢复保险丝与一次性保险丝较量,孰强孰弱
  17. Tenth season fifth episode,Rachel‘s sister came again???????
  18. 德鲁克日志读后感之五十三
  19. 使用k3s部署轻量Kubernetes集群快速教程
  20. C/C++ 与 Python

热门文章

  1. 关于AJAX的ScriptManager.RegisterClientScriptBlock无法弹出对话框的解决方法【归类】
  2. OpenCV3特征提取与目标检测之HOG(一)——HOG的概述与原理
  3. 服务器命令栏不显示,Linux栏 Linux指令(未完)
  4. 国产公链一哥:BUMO技术领先在哪里?
  5. android手机寿命,手机寿命有多长 苹果用3年而安卓只有2年
  6. 2008的最后.期盼
  7. mysql mgr监控_MGR监控报警
  8. 当我不再依赖你的时候说说_「精选」关于依赖一个人的说说()-说说控
  9. 谷歌性能测评工具lighthouse使用
  10. 计算机文件名正确胶卷成功,吴宪