全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

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();
 }
}

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


# android  # 图片验证码  # 自绘控件  # Android利用CountDownTimer实现验证码倒计时效果实例  # Android实现常见的验证码输入框实例代码  # Android实现获取短信验证码并自动填写功能  # Android用 Mob 实现发送短信验证码实例  # Android开发中通过手机号+短信验证码登录的实例代码  # Android 使用fast-verification实现验证码填写功能的实例代码  # 验证码  # 自定义  # 多大  # 重写  # 画上  # 都是  # 随机数  # 是用来  # 只会  # 可以通过  # 或者是  # 三种  # 很明显  # 此项  # 设置为  # 可以得到  # 所占  # 有影响  # 键值  # 有一个 


相关文章: 如何基于云服务器快速搭建个人网站?  可靠的网站设计制作软件,做网站设计需要什么样的电脑配置?  建站主机是否等同于虚拟主机?  制作门户网站的参考文献在哪,小说网站怎么建立?  PHP 500报错的快速解决方法  已有域名建站全流程解析:网站搭建步骤与建站工具选择  招商网站制作流程,网站招商广告语?  如何选购建站域名与空间?自助平台全解析  小建面朝正北,A点实际方位是否存在偏差?  建站主机SSH密钥生成步骤及常见问题解答?  黑客如何通过漏洞一步步攻陷网站服务器?  如何选择PHP开源工具快速搭建网站?  建站之星客服服务时间及联系方式如何?  建站主机与服务器功能差异如何区分?  网站制作知乎推荐,想做自己的网站用什么工具比较好?  再谈Python中的字符串与字符编码(推荐)  如何选择适配移动端的WAP自助建站平台?  个人摄影网站制作流程,摄影爱好者都去什么网站?  小捣蛋自助建站系统:数据分析与安全设置双核驱动网站优化  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  如何有效防御Web建站篡改攻击?  湖北网站制作公司有哪些,湖北清能集团官网?  Bpmn 2.0的XML文件怎么画流程图  成都网站制作公司哪家好,四川省职工服务网是做什么用?  JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)  香港服务器网站卡顿?如何解决网络延迟与负载问题?  建站主机助手选型指南:2025年热门推荐与高效部署技巧  成都品牌网站制作公司,成都营业执照年报网上怎么办理?  如何在IIS7中新建站点?详细步骤解析  道歉网站制作流程,世纪佳缘致歉小吴事件,相亲网站身份信息伪造该如何稽查?  建站之星上传入口如何快速找到?  网站代码制作软件有哪些,如何生成自己网站的代码?  宝塔建站助手安装配置与建站模板使用全流程解析  建站之星如何实现五合一智能建站与营销推广?  洛阳网站制作公司有哪些,洛阳的招聘网站都有哪些?  建站之星下载版如何获取与安装?  教育培训网站制作流程,请问edu教育网站的域名怎么申请?  如何通过虚拟主机快速搭建个人网站?  香港服务器如何优化才能显著提升网站加载速度?  网站制作和推广的区别,想自己建立一个网站做推广,有什么快捷方法马上做好一个网站?  建站之星安装路径如何正确选择及配置?  专业网站制作服务公司,有哪些网站可以免费发布招聘信息?  如何用PHP快速搭建高效网站?分步指南  如何制作一个表白网站视频,关于勇敢表白的小标题?  建站VPS推荐:2025年高性能服务器配置指南  如何通过NAT技术实现内网高效建站?  建站之星免费模板:自助建站系统与智能响应式一键生成  北京网站制作公司哪家好一点,北京租房网站有哪些?  高端企业智能建站程序:SEO优化与响应式模板定制开发  linux top下的 minerd 木马清除方法 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。