热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android自定义View实现验证码

这篇文章主要为大家详细介绍了Android自定义View实现验证码的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

首先我们定义一个declare-styleable标签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 

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_,这样我们就可以直接通过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 

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

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

<&#63;xml version="1.0" encoding="utf-8"&#63;>


 



在根布局添加 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 

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

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


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 将Web服务部署到Tomcat
    本文介绍了如何在JDeveloper 12c中创建一个Java项目,并将其打包为Web服务,然后部署到Tomcat服务器。内容涵盖从项目创建、编写Web服务代码、配置相关XML文件到最终的本地部署和验证。 ... [详细]
  • XNA 3.0 游戏编程:从 XML 文件加载数据
    本文介绍如何在 XNA 3.0 游戏项目中从 XML 文件加载数据。我们将探讨如何将 XML 数据序列化为二进制文件,并通过内容管道加载到游戏中。此外,还会涉及自定义类型读取器和写入器的实现。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 本文详细介绍了 Java 中 org.apache.xmlbeans.SchemaType 类的 getBaseEnumType() 方法,提供了多个代码示例,并解释了其在不同场景下的使用方法。 ... [详细]
  • 本文详细介绍了如何解决MyBatis中常见的BindingException错误,提供了多种排查和修复方法,确保Mapper接口与XML文件的正确配置。 ... [详细]
  • 基于KVM的SRIOV直通配置及性能测试
    SRIOV介绍、VF直通配置,以及包转发率性能测试小慢哥的原创文章,欢迎转载目录?1.SRIOV介绍?2.环境说明?3.开启SRIOV?4.生成VF?5.VF ... [详细]
author-avatar
传说中DE神
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有