欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义控件深入学习 Android生成随机验证码

程序员文章站 2024-02-21 18:47:16
在上一篇的文章中介绍了自定义控件的属性,详情见《详解android自定义控件属性typedarray以及attrs》。那么在这基础上实现随机验证码生成,里面的代码是自定义控...

在上一篇的文章中介绍了自定义控件的属性,详情见《详解android自定义控件属性typedarray以及attrs》。那么在这基础上实现随机验证码生成,里面的代码是自定义控件以及涉及到自定义view绘画。
1、先看实现的效果图


Android自定义控件深入学习 Android生成随机验证码

看到这个效果图是不是感觉还可以。那么就看看源码吧。
2、attr文件

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
 
 <attr name="titletext" format="string" /> 
 <attr name="titletextcolor" format="color" /> 
 <attr name="titletextsize" format="dimension" /> 
 
 <declare-styleable name="authcodeview"> 
  <attr name="titletext" /> 
  <attr name="titletextcolor" /> 
  <attr name="titletextsize" /> 
 </declare-styleable> 
 
</resources> 

3、布局layout

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" 
 xmlns:tools="http://schemas.android.com/tools" 
 xmlns:authcodeview="http://schemas.android.com/apk/res/com.example.authcodeview" 
 android:id="@+id/linearlayout1" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:orientation="vertical" > 
 
 <linearlayout 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" > 
 
  <com.example.authcodeview.view.authcodeview 
   android:id="@+id/authcodeview" 
   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   android:padding="10dp" 
   authcodeview:titletext="3712" 
   authcodeview:titletextcolor="#00ffff" 
   authcodeview:titletextsize="40sp" /> 
 
  <textview 
   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   android:text="点击验证码,换一张" /> 
 </linearlayout> 
 
 <linearlayout 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" > 
 
  <textview 
   android:layout_width="wrap_content" 
   android:layout_height="wrap_content" 
   android:text="输入验证码" /> 
 
  <edittext 
   android:id="@+id/edittext1" 
   android:layout_width="match_parent" 
   android:layout_height="wrap_content" 
   android:ems="10" 
   android:inputtype="number" > 
 
   <requestfocus /> 
  </edittext> 
 </linearlayout> 
 
 <button 
  android:id="@+id/button1" 
  android:layout_width="match_parent" 
  android:layout_height="wrap_content" 
  android:text="验证" /> 
 
</linearlayout> 

4、自定义authcodeview.class
继承view,重写了

onmeasure(int widthmeasurespec, int heightmeasurespec)

ondraw(canvas canvas)方法。
看代码,有详细注释了。

package com.example.authcodeview.view; 
 
import java.util.random; 
 
import com.example.authcodeview.r; 
 
import android.content.context; 
import android.content.res.typedarray; 
import android.graphics.canvas; 
import android.graphics.color; 
import android.graphics.paint; 
import android.graphics.rect; 
import android.util.attributeset; 
import android.util.typedvalue; 
import android.view.view; 
 
public class authcodeview extends view 
{ 
 // 点数设置 
 public static final int point_num = 100; 
 // 线段数设置 
 public static final int line_num = 2; 
 //文本 
 private string mtitletext; 
 // 文本的颜色 
 private int mtitletextcolor; 
 // 文本的大小 
 private int mtitletextsize; 
  
 string[] mchecknum = new string[4]; 
 random random = new random(); 
  
 //绘制时控制文本绘制的范围 
 private rect mbound; 
 private paint mpaint; 
 
 public authcodeview(context context, attributeset attrs) 
 { 
  this(context, attrs, 0); 
 } 
 
 public authcodeview(context context) 
 { 
  this(context, null); 
 } 
 
 /** 
  * 获得我自定义的样式属性 
  * 
  * @param context 
  * @param attrs 
  * @param defstyle 
  */ 
 public authcodeview(context context, attributeset attrs, int defstyle) 
 { 
  super(context, attrs, defstyle); 
  /** 
   * 获得我们所定义的自定义样式属性 
   */ 
  typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.authcodeview, defstyle, 0); 
   
  //获取在attr文件下,名字为authcodeview的declare-styleable属性有几个 
  int n = a.getindexcount(); 
  for (int i = 0; i < n; i++) 
  { 
   int attr = a.getindex(i); 
   switch (attr) 
   { 
   //这个属性可以不要,因为都是随机产生 
   case r.styleable.authcodeview_titletext: 
    mtitletext = a.getstring(attr); 
    break; 
   case r.styleable.authcodeview_titletextcolor: 
    // 默认颜色设置为黑色 
    mtitletextcolor = a.getcolor(attr, color.black); 
    break; 
   case r.styleable.authcodeview_titletextsize: 
    // 默认设置为16sp,typevalue也可以把sp转化为px 
    mtitletextsize = a.getdimensionpixelsize(attr, (int) typedvalue.applydimension( 
      typedvalue.complex_unit_sp, 16, getresources().getdisplaymetrics())); 
    break; 
 
   } 
 
  } 
  a.recycle(); 
   
  mtitletext = randomtext(); 
 
  /** 
   * 获得绘制文本的宽和高 
   */ 
  mpaint = new paint(); 
  mpaint.settextsize(mtitletextsize); 
  mbound = new rect(); 
  mpaint.gettextbounds(mtitletext, 0, mtitletext.length(), mbound); 
 
  this.setonclicklistener(new onclicklistener() 
  { 
 
   @override 
   public void onclick(view v) 
   { 
    mtitletext = randomtext(); 
    postinvalidate(); 
   } 
 
  }); 
 
 } 
  
 //随机产生验证码 
 private string randomtext() 
 { 
  stringbuffer sbreturn = new stringbuffer(); 
  for (int i = 0; i < 4; i++) { 
   stringbuffer sb = new stringbuffer(); 
   int randomint = random.nextint(10); 
   mchecknum[i] = sb.append(randomint).tostring(); 
   sbreturn.append(randomint); 
  } 
   
  return sbreturn.tostring(); 
 } 
  
 //获取验证码 
 public string getauthcode() { 
  return mtitletext; 
 } 
 
 //重写这个方法,设置自定义view控件的大小 
 @override 
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) 
 { 
  // super.onmeasure(widthmeasurespec, heightmeasurespec); 
 
  int width = 0; 
  int height = 0; 
 
  /** 
   * 设置宽度 
   */ 
  int specmode = measurespec.getmode(widthmeasurespec); 
  int specsize = measurespec.getsize(widthmeasurespec); 
  switch (specmode) 
  { 
  case measurespec.exactly:// 明确指定了 
   width = getpaddingleft() + getpaddingright() + specsize; 
   break; 
  case measurespec.at_most:// 一般为warp_content 
   width = getpaddingleft() + getpaddingright() + mbound.width(); 
   break; 
  } 
 
  /** 
   * 设置高度 
   */ 
  specmode = measurespec.getmode(heightmeasurespec); 
  specsize = measurespec.getsize(heightmeasurespec); 
  switch (specmode) 
  { 
  case measurespec.exactly:// 明确指定了 
   height = getpaddingtop() + getpaddingbottom() + specsize; 
   break; 
  case measurespec.at_most:// 一般为warp_content 
   height = getpaddingtop() + getpaddingbottom() + mbound.height(); 
   break; 
  } 
 
  setmeasureddimension(width, height); 
 
 } 
 
 @override 
 protected void ondraw(canvas canvas) 
 { 
  //画背景颜色 
  mpaint.setcolor(color.blue); 
  canvas.drawrect(0, 0, getmeasuredwidth(), getmeasuredheight(), mpaint); 
   
  //划线 
  mpaint.setcolor(mtitletextcolor); 
  int [] line; 
  for(int i = 0; i < line_num; i ++) 
  { 
   //设置线宽 
   mpaint.setstrokewidth(5); 
   line = getline(getmeasuredheight(), getmeasuredwidth()); 
   canvas.drawline(line[0], line[1], line[2], line[3], mpaint); 
  } 
   
  // 绘制小圆点 
  int [] point; 
  int randomint; 
  for(int i = 0; i < point_num; i ++)  
  { 
   //随机获取点的大小 
   randomint = random.nextint(5); 
   point = getpoint(getmeasuredheight(), getmeasuredwidth()); 
   canvas.drawcircle(point[0], point[1], randomint, mpaint); 
  } 
 
  //绘制验证控件上的文本 
  int dx = 20; 
  for(int i = 0; i < 4; i ++){ 
   canvas.drawtext("" + mchecknum[i],dx, getheight() / 2 + getpositon(mbound.height() / 2), mpaint); 
   dx += (getwidth() / 2 - mbound.width() / 2) + i / 5 + 20; 
  } 
//  canvas.drawtext(mtitletext, getwidth() / 2 - mbound.width() / 2, getheight() / 2 + mbound.height() / 2, mpaint); 
 } 
  
 //计算验证码的绘制y点位置 
 private int getpositon(int height) { 
  int temppositoin = (int) (math.random() * height); 
  if (temppositoin < 20) { 
   temppositoin += 20; 
  } 
  return temppositoin; 
 } 
  
 // 随机产生点的圆心点坐标 
 public static int[] getpoint(int height, int width) { 
  int[] tempchecknum = { 0, 0, 0, 0 }; 
  tempchecknum[0] = (int) (math.random() * width); 
  tempchecknum[1] = (int) (math.random() * height); 
  return tempchecknum; 
 } 
  
 //随机产生划线的起始点坐标和结束点坐标 
 public static int[] getline(int height, int width) { 
  int[] tempchecknum = { 0, 0, 0, 0 }; 
  for (int i = 0; i < 4; i += 2) { 
   tempchecknum[i] = (int) (math.random() * width); 
   tempchecknum[i + 1] = (int) (math.random() * height); 
  } 
  return tempchecknum; 
 } 
} 

5、在mainactivity中怎么使用这个自定义authcodeview
package com.example.authcodeview; 
 
import com.example.authcodeview.view.authcodeview; 
import android.os.bundle; 
import android.app.activity; 
import android.view.view; 
import android.view.view.onclicklistener; 
import android.widget.edittext; 
import android.widget.toast; 
 
public class mainactivity extends activity implements onclicklistener 
{ 
 
 private authcodeview mauthcodeview; 
 @override 
 protected void oncreate(bundle savedinstancestate) 
 { 
  super.oncreate(savedinstancestate); 
  setcontentview(r.layout.activity_main); 
   
  initui(); 
 } 
 
 private void initui() { 
  mauthcodeview = (authcodeview)findviewbyid(r.id.authcodeview); 
  findviewbyid(r.id.button1).setonclicklistener(this); 
 } 
 
 @override 
 public void onclick(view v) { 
  switch (v.getid()) { 
  case r.id.button1: 
   edittext edittext = (edittext)findviewbyid(r.id.edittext1); 
   string codestring = edittext.gettext().tostring().trim(); 
   if (codestring.equals(mauthcodeview.getauthcode())) { 
    toast.maketext(this, "验证码验证正确!", toast.length_long).show(); 
   }else { 
    toast.maketext(this, "验证码错误!", toast.length_long).show(); 
   } 
   break; 
 
  default: 
   break; 
  } 
   
 } 
 
 
} 

源码下载:android生成随机验证码demo

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