Android自定义View实现验证码

本文章是基于鸿洋的Android 自定义View (一)的一些扩展,以及对Android自定义View构造函数详解里面内容的一些转载。

首先我们定义一个declare-styleable标签declare-styleable标签的作用是给自定义控件添加自定义属性用的例如这样
(我们定义了文字的颜色,大小,长度,跟背景的颜色)

<declare-styleable name="CustomTitleView">
 <attr name="titleColor" format="color" />
 <attr name="titleSize" format="dimension" />
 <attr name="titleBackground" format="color" />
 <attr name="titleLenth" format="integer" />
 </declare-styleable>

Android提供了自定义属性的方法,其中的format的参数有
(reference、color、boolean、dimension、float、integer、string、fraction、enum、flag)

1.reference:资源ID:
如果设置了这个属性那么这个属性相当于@string|@drawable等调用资源文件的作用
2. color:
这个属性的作用为设置颜色值8或者6位的16进制的颜色值,如设置TextView的textColor等属性的作用相同(如#ff000设置为红色等)
3.boolean:
这个参数的作用为设置true或者false
4.dimension:
这个参数的作用为设置尺寸值,如px、dip、dp、sp等
5.float:
这个参数的作用为设置浮点型数据
6.integer:
这个参数的作用为设置整形数据
7.string:
这个参数的作用为设置字符串数据,如TextView的text属性
8.fraction:
这个参数的作用为设置百分比数据
9:enum:
这个参数相当于给这个attr的name属性设置固定的参数,如线性布局的orientation属性只能设置vertical或者horizontal
10:flag:
这个参数作用为:位或运算

一个自定义View的步骤为

1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
3、重写onMeasure
4、重写onDraw

有的时候onMeasure方法是不用重写的例如系统自带组件等
然后我们定义一下需要的属性

 //文本
 private StringBuffer mTitleText;
 //文本的颜色
 private int mTitleColor;
 //文本的大小
 private int mTitleSize;
 //背景颜色
 private int mBackground;
 //控制生成的随机字符串长度
 private int mLenth;
 //绘制时控制文本绘制的范围
 private Rect mBound;
 //画笔
 private Paint mPaint;
 //随机数对象
 private Random random = new Random();
 //字符串边距
 private int padding_left;
 //随机的值
 String[] data = {"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",
  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};

然后我们重写三个构造方法,我们需要注意的是

1、在代码中直接new一个自定义View实例的时候,会调用第一个构造函数.
2、在xml布局文件中调用自定义View的时候,会调用第二个构造函数.
3、在xml布局文件中调用自定义View,并且自定义标签中还有自定义属性时,这里调用的还是第二个构造函数.

也就是说,系统默认只会调用Custom View的前两个构造函数,至于第三个构造函数的调用,通常是我们自己在构造函数中主动调用的(例如,在第二个构造函数中调用第三个构造函数).
至于自定义属性的获取,通常是在构造函数中通过obtainStyledAttributes函数实现的。

public CustomTitleView(Context context) {
 this(context, null);
 }

 public CustomTitleView(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 setOnClickListener(this);
 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomTitleView);
 int n = typedArray.getIndexCount();
 for (int i = 0; i < n; i++) {
  int attr = typedArray.getIndex(i);
  switch (attr) {
  case R.styleable.CustomTitleView_titleColor:
   mTitleColor = typedArray.getColor(attr, Color.BLACK);
   break;
  case R.styleable.CustomTitleView_titleSize:
   mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
   break;
  case R.styleable.CustomTitleView_titleBackground:
   mBackground = typedArray.getColor(attr, Color.BLACK);
   break;
  case R.styleable.CustomTitleView_titleLenth:
   mLenth = typedArray.getInteger(attr, 4);
   break;
  }
 }
 //回收
 typedArray.recycle();
 mPaint = new Paint();
 randomText();
 mPaint.setTextSize(mTitleSize);
 //创建一个矩形
 mBound = new Rect();
 //第一个参数为要测量的文字,第二个参数为测量起始位置,第三个参数为测量的最后一个字符串的位置,第四个参数为rect对象
 mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound);
 }

obtainStyledAttributes的第二个属性为调用你刚在在attrs.xml文件里生命的declare-styleable标签的name
然后我们重写一下onMeasure方法,通过getMeasuredLength方法计算出宽和高

/**
 * 计算宽高
 *
 * @param lenth widthMeasureSpec或heightMeasureSpec
 * @param isWidth true为计算宽度,false为计算高度
 */
 private int getMeasuredLength(int lenth, boolean isWidth) {
 if (isWidth) {
  if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) {
  //设置了精确尺寸,通过MeasureSpec.getSize()获得尺寸返回宽度
  return MeasureSpec.getSize(lenth);
  } else {
  //设置了warp_content,则需要我们自己计算
  /**
   * 首先给画笔设置文字大小
   * 通过getTextBounds方法获得绘制的Text的宽度
   * 然后因为我们的自定义View只有一个text所以我们只需要getPaddingLeft()+getPaddingRight()+textwidth即可计算出显示出view所需要最小的宽度
   * 一般计算宽度为getPaddingLeft()+getPaddingRight()+自己绘画的文字或者图片的宽度,因为计算的是所需宽度,假设我们绘制了图片+文字,那么就需要判断图片的宽度跟文字的宽度那个更大比如getPaddingLeft()+getPaddingRight()+Math.max(图片的宽度,文字的宽度)即得出所需宽度
   */
  if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) {
   mPaint.setTextSize(mTitleSize);
   mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound);
   float textwidth = mBound.width();
   int desired = (int) (getPaddingLeft() + textwidth + getPaddingRight());
   return Math.min(desired,MeasureSpec.getSize(lenth));
  }

  }
 } else {
  if (MeasureSpec.getMode(lenth) == MeasureSpec.EXACTLY) {
  //用户设置了精确尺寸,通过MeasureSpec.getSize()获得尺寸返回高度
  return MeasureSpec.getSize(lenth);
  } else {
  if (MeasureSpec.getMode(lenth) == MeasureSpec.AT_MOST) {
   //设置了warp_content,则需要我们自己计算
   mPaint.setTextSize(mTitleSize);
   mPaint.getTextBounds(mTitleText.toString(), 0, mTitleText.length(), mBound);
   float texthgeight = mBound.height();
   int desired = (int) (getPaddingTop() + texthgeight + getPaddingBottom());
   return Math.min(desired,MeasureSpec.getSize(lenth));
  }
  }
 }
 return 0;
 }

然后在onMeasure方法里调用

@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 setMeasuredDimension(getMeasuredLength(widthMeasureSpec, true), getMeasuredLength(heightMeasureSpec, false));
 }

系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMeasure方法

重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用

在这里有些初学者可能不理解getMode跟getSize的作用,首先getMode()用于判断宽高设置的模式,获得到之后即可判断,例如

//xx表示widthMeasureSpec或者heightMeasureSpec

if(MeasureSpec.getMode(xx)==MeasureSpec.EXACTLY){
 //进入这里则代表设置了match_parent或者将控件的layout_width或layout_height指定为具体数值时如andorid:layout_width="100dp",这样我们就可以直接通过MeasureSpec.getSize(xx)方法获得宽或高
}else if(MeasureSpec.getMode(xx)==MeasureSpec.EXACTLY){
 //进入这里代表设置了wrap_content,那么则需要我们自己计算宽或高
}else{
 //进入这个则代表代表是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,通过measure方法传入的模式
}

然后我们重写一下onDraw方法、

 @Override
 protected void onDraw(Canvas canvas) {
 super.onDraw(canvas);
 padding_left = 0;
 mPaint.setColor(mBackground);
 canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
 mPaint.setColor(mTitleColor);
 for (int i = 0; i < mTitleText.length(); i++) {
  randomTextStyle(mPaint);
  padding_left += mPaint.measureText(String.valueOf(mTitleText.charAt(i)))+10;
  canvas.drawText(String.valueOf(mTitleText.charAt(i)), padding_left, getHeight() / 2 + mBound.height() / 2, mPaint);
 }
 }
private void randomTextStyle(Paint paint) {
 paint.setFakeBoldText(random.nextBoolean()); //true为粗体,false为非粗体
 float skewX = random.nextInt(11) / 10;
 skewX = random.nextBoolean() ? skewX : -skewX;
 paint.setTextSkewX(skewX); //float类型参数,负数表示右斜,整数左斜
 paint.setUnderlineText(true); //true为下划线,false为非下划线
 paint.setStrikeThruText(false); //true为删除线,false为非删除线
 }

这里绘制了多个字符串,并且使每个绘制的字符串都歪歪扭扭的,这样我们采用randomTextStyle()即可在每次绘制字符的时候设置每个字符都为不同的样式,在这里我们讲一下drawText的几个参数,第一个参数就是要绘制的文字内容,第二个参数为x轴,作用相当于左边距,第三个参数为Y轴,第四个参数为paint的实例,我的朋友具体讲了一下drawText的绘制坐标有兴趣的可以去看一下android canvas drawText()文字居中

最后我们在布局文件中引用我们的自定义view

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:cq="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="horizontal">

 <chapter.com.rxjavachapter.CustomTitleView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_centerInParent="true"
 android:padding="10dp"
 cq:titleBackground="@android:color/black"
 cq:titleColor="#ff0000"
 cq:titleLenth="4"
 cq:titleSize="10sp" />

</RelativeLayout>

在根布局添加 xmlns:xx=”http://schemas.android.com/apk/res-auto” 这里的xx可以是任何字母
然后用xx去点我们在attr的name去设值,最后实现出的效果是这样

既然是验证码view,那么我们自然要开放出点击改变验证码内容的点击事件,在第三个构造方法中添加click事件

 @Override
 public void onClick(View v) {
 randomText();
 postInvalidate();
 }
/**
 * 获得随机的字符串
 *
 * @return
 */
 private void randomText() {
 mTitleText = new StringBuffer();
 for (int i = 0; i < mLenth; i++) {
  mTitleText.append(data[(int) (Math.random() * data.length)]);
 }
 }

 /**
 * 获得到随机的值
 *
 * @return
 */
 public String getCode() {
 return mTitleText.toString();
 }

 /**
 * 判断是否相同
 *
 * @return
 */
 public boolean isEqual(String code) {
 if (code != null) {
  return code.toUpperCase().equals(getCode().toUpperCase()) ? true : false;
 } else {
  return false;
 }
 }

这样就可以点击改变一次验证码内容了,并且我们开放出两个方法作为判断验证码或得到验证码,我这只是简单的一个验证码,大家可以自己加入更多的东西。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android自定义view制作绚丽的验证码

    废话不多说了,先给大家展示下自定义view效果图,如果大家觉得还不错的话,请继续往下阅读. 怎么样,这种验证码是不是很常见呢,下面我们就自己动手实现这种效果,自己动手,丰衣足食,哈哈~ 一. 自定义view的步骤 自定义view一直被认为android进阶通向高手的必经之路,其实自定义view好简单,自定义view真正难的是如何绘制出高难度的图形,这需要有好的数学功底(后悔没有好好学数学了~),因为绘制图形经常要计算坐标点及类似的几何变换等等.自定义view通常只需要以下几个步骤: 写一个类继承

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

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

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

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

  • Android自定义View绘制随机生成图片验证码

    本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注意的地方. 按照惯例先看看效果图: 一.先总结下自定义View的步骤: 1.自定义View的属性 2.在View的构造方法中获得我们自定义的属性 3.重写onMesure 4.重写onDraw 其中onMesure方法不一定要重写,但大部分情况下还是需要重写的 二.View 的几个构造函数 1.public CustomV

  • Android自定义View实现随机验证码

    对于android开发来说自定义View还是一个比较重要的技能,所以在这里写一篇自定义View入门的文章,也是实现一个相对简单的随机产生验证码的功能: 自定义View主要也就分为几步  1.自定义View的属性  2.在我们的自定义的布局中获取自定义属性  3.重写onMesure方法  4.重写onDraw方法 好现在我们就一步一步的来,首先创建我们的View属性 在valuse目录下创建一个attrs.xml的文件,然后: <?xml version="1.0" encodi

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

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

  • Android开发之获取短信验证码后按钮背景变化并且出现倒计时

    目前越来越多的app在注册或是进行对应操作时,要求获取短信验证码,在点击了获取短信验证码的按钮后,就是出现倒计时,比如倒计时120S,在倒计时期间内,按钮背景变化并且出现倒计时,当倒计时结束后,如果你没有获取到验证码,可以再次点击. 代码如下所示: VerCodeTimer mVerCodeTimer=(Button) findViewById(R.id.login_get_ver_code); private class VerCodeTimer extends CountDownTimer

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

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

  • Android通过自定义View实现随机验证码

    很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章. 一.问题描述 熟悉web开发中童鞋们都知道为了防止恶意破解.恶意提交.刷票等我们在提交表单数据时,都会使用随机验证码功能.在Android应用中我们同样需要这一功能,该如何实现呢,下面我们就自定义一个随机验证码View控件实现这一需求,并且具备通用性,需要的时候在界面中直接加入这个View组件即可. 二.案例介绍 案例运行效

  • Android实现自动提取短信验证码功能

    本文实例讲解了Android自动提取短信验证码解决方案,分享给大家供大家参考,具体内容如下 主要功能及优点 1.收到验证码短信后,自动提取短信中的验证码填写到相应输入框 2.可指定一个号码,只读取与他有关短信,避免提取来源错误 3.利用正则表达式,可匹配各种类型验证码 模块集成关键步骤     将auto_getcode_demo中src包里的SMSContentObserver类复制到你的项目src包中 在SMSContentObserver中:    修改正则表达式内容来匹配自己想要获取的字

随机推荐