android实现图片验证码方法解析(自绘控件)

自绘控件的内容都是自己绘制出来的 大致流程如下:

1.定义一个类继承view

1.使用TypedArray初始化属性集合
    在view的构造方法中 有一个AttributeSet的参数 很明显是用来保存控件属性信息的 我们也的确可以通过循环然后用键值对的方式获取信息 而TypedArray是用来简化我们的工作的

2.重写onMeasure 测量控件大小

3.重写onDraw 绘制控件

2.根据需求在attrs文件中自定义属性

declare-styleable 声明自定义属性可以自定义一个新属性也可以引用已经存在的属性两者的区别就是新属性需要添加format进行类型的定义

3.在activity的布局文件使用

自定义图片验证码 演示效果

示例代码

 <declare-styleable name="VerifyCode">
 <attr name="codeTextSize" format="dimension"/>
 <attr name="codeBackground" format="color"/>
 <attr name="codeLength" format="integer"/>
 <attr name="isContainChar" format="boolean"/>
 <attr name="pointNum" format="integer"/>
 <attr name="linNum" format="integer"/>
 </declare-styleable>
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import java.util.Random;
/**
 * 类描述:自定义验证码
 * 创建者:lb
 */
public class VerifyCode extends View {
 private String mCodeText;//文本内容
 private int mCodeTextSize;//文本大小
 private int mCodeLength;//验证码长度
 private int mCodeBackground;//背景色
 private boolean isContainChar;//验证码是否包含字母
 private int mPointNum;//干扰点数
 private int mLineNum;//干扰线数
 private Paint mPaint;//画笔
 private Rect mBound;//绘制范围
 private Bitmap bitmap;//验证码图片
 private static Random mRandom = new Random();
 private static int mWidth;//控件的宽度
 private static int mHeight;//控件的高度
 public VerifyCode(Context context) {
 super(context);
 }
 public VerifyCode(Context context, AttributeSet attrs) {
 super(context, attrs);
 initAttrValues(context,attrs);
 initData();
 }
 /**
 * 初始化属性集合
 * @param context
 * @param attrs
 */
 private void initAttrValues(Context context, AttributeSet attrs){
 // //获取在AttributeSet中定义的 VerifyCode 中声明的属性的集合
 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerifyCode);
 //获取TypeArray的长度
 int count=typedArray.getIndexCount();
 for (int i=0;i<count;i++){
  //获取此项属性的ID
  int index=typedArray.getIndex(i);
  switch (index){
  case R.styleable.VerifyCode_codeTextSize:
   // 默认设置为16sp,TypeValue类 px转sp 一个转换类
   mCodeTextSize =typedArray.getDimensionPixelSize(index,(int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
   break;
  case R.styleable.VerifyCode_codeBackground:
mCodeBackground=typedArray.getColor(index,Color.WHITE);
   break;
  case R.styleable.VerifyCode_codeLength:
   mCodeLength=typedArray.getInteger(index,4);
   break;
  case R.styleable.VerifyCode_isContainChar:
   isContainChar=typedArray.getBoolean(index,false);
   break;
  case R.styleable.VerifyCode_pointNum:
   mPointNum=typedArray.getInteger(index,100);
   break;
  case R.styleable.VerifyCode_linNum:
   mLineNum=typedArray.getInteger(index,3);
   break;
  }
 }
 //Recycles the TypedArray, to be re-used by a later caller
 //官方解释:回收TypedArray 以便后面的使用者重用
 typedArray.recycle();
 }
 /**
 * 初始化数据
 */
 private void initData(){
 mCodeText=getValidationCode(mCodeLength,isContainChar);
 mPaint=new Paint();
 mPaint.setAntiAlias(true);
 mBound=new Rect();
 //计算文字所在矩形,可以得到宽高
 mPaint.getTextBounds(mCodeText,0, mCodeText.length(),mBound);
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 //获取控件宽高的显示模式
 int widthMode=MeasureSpec.getMode(widthMeasureSpec);
 int heightMode=MeasureSpec.getMode(heightMeasureSpec);
 //获取宽高的尺寸值 固定值的宽度
 int widthSize=MeasureSpec.getSize(widthMeasureSpec);
 int heightSize=MeasureSpec.getSize(heightMeasureSpec);
 //设置宽高默认为建议的最小宽高
 int width= getDefaultSize(getSuggestedMinimumWidth(),widthMeasureSpec) ;
 int height=getDefaultSize(getSuggestedMinimumHeight(),heightMeasureSpec);

// MeasureSpec父布局传递给后代的布局要求 包含 确定大小和三种模式
// EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
// AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
// UNSPECIFIED:表示子布局想要多大就多大,很少使用
 if (widthMode==MeasureSpec.EXACTLY){
  width=widthSize;
 }else{
  mPaint.setTextSize(mCodeTextSize);
  mPaint.getTextBounds(mCodeText,0,mCodeText.length(),mBound);
  float textWidth=mBound.width();
  int tempWidth=(int)(getPaddingLeft()+textWidth+getPaddingRight());
  width=tempWidth;
 }
 if (heightMode == MeasureSpec.EXACTLY)
 {
  height = heightSize;
 } else
 {
  mPaint.setTextSize(mCodeTextSize);
  mPaint.getTextBounds(mCodeText, 0, mCodeText.length(), mBound);
  float textHeight = mBound.height();
  int tempHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom());
  height = tempHeight;
 }
 //设置测量的宽高
 setMeasuredDimension(width,height);
 }
 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 mWidth=getWidth();
 mHeight=getHeight();

 if (bitmap==null){
  bitmap=createBitmapValidate();
 }
 canvas.drawBitmap(bitmap,0,0,mPaint);
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 switch (event.getAction()){
  case MotionEvent.ACTION_DOWN:
  refresh();
  break;
 }
 return super.onTouchEvent(event);
 }
 /**
 * 创建图片验证码
 * @return
 */
 private Bitmap createBitmapValidate(){
 if(bitmap != null && !bitmap.isRecycled()){
  //回收并且置为null
  bitmap.recycle();
  bitmap = null;
 }
 //创建图片
 Bitmap sourceBitmap=Bitmap.createBitmap(mWidth,mHeight, Bitmap.Config.ARGB_8888);
 //创建画布
 Canvas canvas=new Canvas(sourceBitmap);
 //画上背景颜色
 canvas.drawColor(mCodeBackground);
 //初始化文字画笔
 mPaint.setStrokeWidth(3f);
 mPaint.setTextSize(mCodeTextSize);
 //测量验证码字符串显示的宽度值
 float textWidth=mPaint.measureText(mCodeText);
 //画上验证码
 int length = mCodeText.length();
 //计算一个字符的所占位置
 float charLength = textWidth / length;
 for (int i = 1; i <= length; i++) {
  int offsetDegree = mRandom.nextInt(15);
  //这里只会产生0和1,如果是1那么正旋转正角度,否则旋转负角度
  offsetDegree = mRandom.nextInt(2) == 1 ? offsetDegree : -offsetDegree;
  //用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。
  canvas.save();
  //设置旋转
  canvas.rotate(offsetDegree, mWidth / 2, mHeight / 2);
  //给画笔设置随机颜色
  mPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20,
   mRandom.nextInt(200) + 20);
  //设置字体的绘制位置
  canvas.drawText(String.valueOf(mCodeText.charAt(i - 1)), (i - 1) * charLength+5,
   mHeight * 4 / 5f, mPaint);
  //用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。
  canvas.restore();
 }
 //重新设置画笔
 mPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20,
  mRandom.nextInt(200) + 20);
 mPaint.setStrokeWidth(1);
 //产生干扰效果1 -- 干扰点
 for (int i = 0; i < mPointNum; i++) {
  drawPoint(canvas, mPaint);
 }
 //生成干扰效果2 -- 干扰线
 for (int i = 0; i < mLineNum; i++) {
  drawLine(canvas, mPaint);
 }
 return sourceBitmap;
 }
 /**
 * 生成干扰点
 */
 private static void drawPoint(Canvas canvas, Paint paint) {
 PointF pointF = new PointF(mRandom.nextInt(mWidth) + 10, mRandom.nextInt(mHeight) + 10);
 canvas.drawPoint(pointF.x, pointF.y, paint);
 }
 /**
 * 生成干扰线
 */
 private static void drawLine(Canvas canvas, Paint paint) {
 int startX = mRandom.nextInt(mWidth);
 int startY = mRandom.nextInt(mHeight);
 int endX = mRandom.nextInt(mWidth);
 int endY = mRandom.nextInt(mHeight);
 canvas.drawLine(startX, startY, endX, endY, paint);
 }
 /**
 * 获取验证码
 *
 * @param length 生成随机数的长度
 * @param contains 是否包含字符串
 * @return
 */
 public String getValidationCode(int length,boolean contains) {
 String val = "";
 Random random = new Random();
 for (int i = 0; i < length; i++) {
  if (contains){
  //字母或数字
  String code = random.nextInt(2) % 2 == 0 ? "char" : "num";
  //字符串
  if ("char".equalsIgnoreCase(code)) {
   //大写或小写字母
   int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
   val += (char) (choice + random.nextInt(26));
  } else if ("num".equalsIgnoreCase(code)) {
   val += String.valueOf(random.nextInt(10));
  }
  }else{
  val += String.valueOf(random.nextInt(10));
  }
 }
 return val;
 }
 /**
 *判断验证码是否一致 忽略大小写
 */
 public Boolean isEqualsIgnoreCase(String CodeString) {
 return mCodeText.equalsIgnoreCase(CodeString);
 }
 /**
 * 判断验证码是否一致 不忽略大小写
 */
 public Boolean isEquals(String CodeString) {
 return mCodeText.equals(CodeString);
 }
 /**
 * 提供外部调用的刷新方法
 */
 public void refresh(){
 mCodeText= getValidationCode(mCodeLength,isContainChar);
 bitmap = createBitmapValidate();
 invalidate();
 }
}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • Android获取短信验证码的实现方法

    先给大家展示下效果图,如果感觉不错,请参考实现思路详解 Android开发中关于短息验证码的设计层出不穷,越来越多的应用为了更好的提高软件的安全性,开始使用通过服务器向用户发送验证码的方式,来保护用户个人信息的安全性.无论是用户注册时的信息验证还是当用户发出找回密码请求时的短信验证,他们的工作原理大致上是一致的,因为项目的需要研究了一下关于这方面的知识,本篇我将带领大家一起实现这一当下流行的设计方案. 众所周知,短信验证需要服务器端生成一个验证码,然后发送到用户输入的手机上,这个过程需要服务器主

  • Android​短信验证码倒计时验证的2种常用方式

    前言 ​本文主要介绍的是短信验证码功能,这里总结了两种常用的方式,可以直接拿来使用. 看图 计时器 说明:这里的及时从10开始,是为了演示的时间不要等太长而修改的. 方法如下 1.第一种方式:Timer /** * Description:自定义Timer * <p> * Created by Mjj on 2016/12/4. */ public class TimeCount extends CountDownTimer { private Button button; //参数依次为总时

  • Android开发工程中集成mob短信验证码功能的方法

    一.前言 现在的app基本上都需要用到短信功能,注册时或者有消息通知时需要给用户发送一条短信,但是对于个人开发者来说,去买第三方的短信服务实在是有点奢侈,很好的是mob为我们提供了免费的短信验证码服务功能,我不是打广告,的确觉得这项服务很不错.那么下面就简单讲一下如何在自己的工程里集成mob的短信功能,其实整个流程并不复杂,只是个人觉得mob的官方文档有点小乱,官方Demo也有点小复杂,同时有一些细节地方容易被忽视,也会导致一些问题. PS:太喜欢mob的logo了. 二.实现过程 本篇只涉及A

  • Android实现短信验证码获取自动填写功能(详细版)

    现在的应用在注册登录或者修改密码中都用到了短信验证码,那在android中是如何实现获取短信验证码并自动填写的呢? 首先,需要要在manifest中注册接收和读取短信的权限: <uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission> <uses-permission android:name="android.permission.READ_

  • Android绘制验证码的实例代码

    在前面仿华为加载动画.仿网易音乐听歌识曲-麦克风动画中,我们通过绘图的基础知识完成了简单的绘制.在本例中,我们将绘制常见的验证码. 一.效果图 二.知识点与思路分析 通过上面的效果图观察,我们可以看到里面有绘制的随机线条,随机绘制的验证码. 绘制线条,直线或曲线 绘制文本,生成的验证码文本的绘制 绘制圆点. 三.代码编写 /** * Created by Iflytek_dsw on 2017/7/3. */ public class IdentifyCodeUtil { private sta

  • Android如何通过手机获取验证码来完成注册功能

    注册很多app或者网络账户的时候,经常需要手机获取验证码,来完成注册,那时年少,只是觉得手机获取验证码这件事儿很好玩,并没有关心太多,她是如何实现的,以及她背后的故事到底是什么样子的,现在小编接手的这个项目里面,就需要通过手机号进行注册,并且手机号发送相应的验证码,来完成注册,那么在一些应用app里面到底是如何实现点击按钮获取验证码,来完成注册这整个流程的呢?今天小编就以注册为例,和小伙伴们分享一下,如何通过手机号获取验证码来完成注册的一整套流程以及如何采用正则表达式来验证手机号码是否符合电信.

  • Android中用Bmob实现短信验证码功能的方法详解

    这篇文章主要介绍发送验证码和校验验证码的功能,用到一个第三方平台Bmob,那Bmob是什么呢?Bmob可以开发一个云存储的移动应用软件,他提供了大量的标准的API接口,根据需要接入相关服务,开发者可以更加专注于应用的开发,让产品交付更快速,验证码功能就是其中一个. 一.跟其他第三方一样,我们开发之前要做一些准备工作. 1.首先,去官网注册一个帐号:http://www.bmob.cn/: 2.然后就可以创建应用了:具体怎么做Bmob说得很清楚了(官方操作介绍),如果你不想看,我简单说一下:点击右

  • Android获取和读取短信验证码的实现方法

    现如今,验证码在Android的客户端还是非常普遍的.通过手机账号和验证码直接去注册应用账户的信息.很多应用都以这种方式来完成注册.简单的介绍一下吧. Android获取短信验证码还是比较简单的,通过Mob官网提供的ShareSDK,调用其中内部的方法,就可以获取到短信的验证码了.提供一下Mob的官网地址.http://www.mob.com/#/在官网上注册相关的信息之后,下载相关的jar包和.so文件就可以实现获取短信验证码了(2.0之前的版本都需要下载jar包和 .so文件,而现在的2.2

  • Android实现短信验证码自动填写功能

    本实例为大家分享了Android实现短信验证码自动填写功能,供大家参考,具体内容如下 实现思路很简单: 1.在需要输入验证码的Activity代码注册监听短信的广播 2.拦截短信,获取其中的验证码 3.回写到EditText private SmsReciver smsReciver = new SmsReciver(); /** 收到短信Action **/ String ACTION_SMS_RECIVER = "android.provider.Telephony.SMS_RECEIVED

  • Android 高仿斗鱼滑动验证码

    如下图.在Android上实现起来就不太容易,有些效果还是不如web端酷炫.) 我们的Demo,Ac娘镇楼 (图很渣,也忽略底下的SeekBar,这不是重点) 一些动画,效果录不出来了,大家可以去斗鱼web端看一下,然后下载Demo看一下,效果还是可以的. 代码 传送门: https://github.com/mcxtzhang/SwipeCaptcha 我们的Demo和web端基本上一样. 那么本控件包含不仅包含以下功能: 随机区域起点(左上角x,y)生成一个验证码阴影.验证码拼图 凹凸图形会

随机推荐