广告
返回顶部
首页 > 资讯 > 移动开发 >Android自定义View绘制随机生成图片验证码
  • 356
分享到

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

view图片验证码Android 2022-06-06 07:06:28 356人浏览 安东尼
摘要

本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注

本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注意的地方。

按照惯例先看看效果图:


一、先总结下自定义View的步骤:

1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
3、重写onMesure
4、重写onDraw
其中onMesure方法不一定要重写,但大部分情况下还是需要重写的

二、View 的几个构造函数

1、public CustomView(Context context)
—>java代码直接new一个CustomView实例的时候,会调用这个只有一个参数的构造函数;
2、public CustomView(Context context, AttributeSet attrs)
—>在默认的XML布局文件中创建的时候调用这个有两个参数的构造函数。AttributeSet类型的参数负责把XML布局文件中所自定义的属性通过AttributeSet带入到View内;
3、public CustomView(Context context, AttributeSet attrs, int defStyleAttr)
—>构造函数中第三个参数是默认的Style,这里的默认的Style是指它在当前Application或者Activity所用的Theme中的默认Style,且只有在明确调用的时候才会调用
4、public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
—>该构造函数是在api21的时候才添加上的

三、下面我们就开始来看看代码啦

1、自定义View的属性,首先在res/values/ 下建立一个attr.xml , 在里面定义我们的需要用到的属性以及声明相对应属性的取值类型


<?xml version="1.0" encoding="utf-8"?>
<resources>
 <attr name="text" fORMat="string" />
 <attr name="textColor" format="color" />
 <attr name="textSize" format="dimension" />
 <attr name="bGColor" format="color" />
 <declare-styleable name="CustomView">
  <attr name="text" />
  <attr name="textColor" />
  <attr name="textSize" />
  <attr name="bgColor" />
 </declare-styleable>
</resources>

我们定义了字体,字体颜色,字体大小以及字体的背景颜色4个属性,format是值该属性的取值类型,format取值类型总共有10种,包括:string,color,demension,integer,enum,reference,float,boolean,fraction和flag。

2、然后在XML布局中声明我们的自定义View


<RelativeLayout xmlns:android="Http://schemas.android.com/apk/res/android"
 xmlns:custom="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent">
 <com.per.customview01.view.CustomView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_centerInParent="true"
  android:padding="10dp"
  custom:bgColor="#FF27FF28"
  custom:text="J2RdWQG"
  custom:textColor="#ff0000"
  custom:textSize="36dp" />
</RelativeLayout>

一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”,Android Studio中我们可以使用res-atuo命名空间,就不用在添加自定义View全类名。

3、在View的构造方法中,获得我们的自定义的样式



 private String mText;
 
 private int mTextColor;
 
 private int mTextSize;
 
 private int mBgCplor;
 private Rect mBound;
 private Paint mPaint;
 public CustomView(Context context) {
  this(context, null);
 }
 public CustomView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  
  TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0);
  for (int i = 0; i < a.getIndexCount(); i++) {
   int attr = a.getIndex(i);
   switch (attr) {
    case R.styleable.CustomView_text:
     mText = a.getString(attr);
     break;
    case R.styleable.CustomView_textColor:
     // 默认文本颜色设置为黑色
     mTextColor = a.getColor(R.styleable.CustomView_textColor, Color.BLACK);
     break;
    case R.styleable.CustomView_bgColor:
     // 默认文本背景颜色设置为蓝色
     mBgCplor = a.getColor(R.styleable.CustomView_bgColor, Color.BLUE);
     break;
    case R.styleable.CustomView_textSize:
     // 默认设置为16sp,TypeValue也可以把sp转化为px
     mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
     break;
   }
  }
  a.recycle();
  // 获得绘制文本的宽和高
  mPaint = new Paint();
  mPaint.setTextSize(mTextSize);
  mBound = new Rect();
  mPaint.getTextBounds(mText, 0, mText.length(), mBound);
 }

我们重写了3个构造方法,在上面的构造方法中说过默认的布局文件调用的是两个参数的构造方法,所以记得让所有的构造方法调用三个参数的构造方法,然后在三个参数的构造方法中获得自定义属性。
一开始一个参数的构造方法和两个参数的构造方法是这样的:


 public CustomView(Context context) {
  super(context);
 }
 public CustomView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

有一点要注意的是super应该改成this,然后让一个参数的构造方法引用两个参数的构造方法,两个参数的构造方法引用三个参数的构造方法,代码如下:


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

4、重写onDraw,onMesure方法


@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 }
 @Override
 protected void onDraw(canvas canvas) {
  super.onDraw(canvas);
  mPaint.setColor(mBgCplor);
  canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
  mPaint.setColor(mTextColor);
  canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
 }

View的绘制流程是从ViewRoot的performTravarsals方法开始的,经过measure、layout和draw三个过程才能最终将一个View绘制出来,其中:
 •测量——onMeasure():用来测量View的宽和高来决定View的大小
 •布局——onLayout():用来确定View在父容器ViewGroup中的放置位置
 •绘制——onDraw():负责将View绘制在屏幕上

来看下此时的效果图


细心的朋友会发现,在上面的布局文件中,我们是把宽和高设置为wrap_content的,可是这个效果图怎么看都不是我们想要的,这是因为系统帮我们测量的高度和宽度默认是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,这个是对的。但是除了设置明确的宽度和高度,不管我们设置为WRAP_CONTENT还是MATCH_PARENT,系统帮我们测量的结果就是MATCH_PARENT,所以,当我们设置了WRAP_CONTENT时,我们需要自己进行测量,也就是说我们需要重写onMesure方法

下面是我们重写onMeasure代码:


 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heighMode = MeasureSpec.getMode(heightMeasureSpec);
  int heighSize = MeasureSpec.getSize(heightMeasureSpec);
  setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : getPaddingLeft() + getPaddingRight() + mBound.width(), heighMode == MeasureSpec.EXACTLY ? heighSize : getPaddingTop() + getPaddingBottom() + mBound.height());
 }

MeasureSpec封装了父布局传递给子布局的布局要求,MeasureSpec的specMode一共有三种模式:
(1)EXACTLY(完全):一般是设置了明确的值或者是MATCH_PARENT,父元素决定了子元素的大小,子元素将被限定在给定的范围里而忽略它本身大小;
(2)AT_MOST(至多):表示子元素至多达到给定的一个最大值,一般为WARP_CONTENT;

我们再看看效果图:

现在这个是我们想要的结果了吧,回归到主题,今天讲的是自定义View之随机生成图片验证码,现在把自定义View的部分完成了,我把完整的代码贴出来


package com.per.customview01.view;
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.Log;
import android.util.TypedValue;
import android.view.View;
import com.per.customview01.R;
import java.util.Random;

public class CustomView extends View {
 private static final char[] CHARS = {'0', '1', '2', '3', '4', '5', '6',
   '7', '8', '9', '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'};
 
 private Random mRandom = new Random();
 
 private StringBuffer sb = new StringBuffer();
 
 private String mText;
 
 private int mTextColor;
 
 private int mTextSize;
 
 private int mBgCplor;
 private Rect mBound;
 private Paint mPaint;
 public CustomView(Context context) {
  this(context, null);
 }
 public CustomView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }
 public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  
  TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0);
  for (int i = 0; i < a.getIndexCount(); i++) {
   int attr = a.getIndex(i);
   switch (attr) {
    case R.styleable.CustomView_text:
     mText = a.getString(attr);
     break;
    case R.styleable.CustomView_textColor:
     // 默认文本颜色设置为黑色
     mTextColor = a.getColor(R.styleable.CustomView_textColor, Color.BLACK);
     break;
    case R.styleable.CustomView_bgColor:
     // 默认文本背景颜色设置为蓝色
     mBgCplor = a.getColor(R.styleable.CustomView_bgColor, Color.BLUE);
     break;
    case R.styleable.CustomView_textSize:
     // 默认设置为16sp,TypeValue也可以把sp转化为px
     mTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
     break;
   }
  }
  a.recycle();
  // 获得绘制文本的宽和高
  mPaint = new Paint();
  mPaint.setTextSize(mTextSize);
  mBound = new Rect();
  mPaint.getTextBounds(mText, 0, mText.length(), mBound);
  this.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    mText = createCode();
    mTextColor = randomColor();
    mBgCplor = randomColor();
    //View重新调用一次draw过程,以起到界面刷新的作用
    postInvalidate();
   }
  });
 }
 
 public String createCode() {
  sb.delete(0, sb.length()); // 使用之前首先清空内容
  for (int i = 0; i < 6; i++) {
   sb.append(CHARS[mRandom.nextInt(CHARS.length)]);
  }
  Log.e("生成验证码", sb.toString());
  return sb.toString();
 }
 
 private int randomColor() {
  sb.delete(0, sb.length()); // 使用之前首先清空内容
  String haxString;
  for (int i = 0; i < 3; i++) {
   haxString = Integer.toHexString(mRandom.nextInt(0xFF));
   if (haxString.length() == 1) {
    haxString = "0" + haxString;
   }
   sb.append(haxString);
  }
  Log.e("随机颜色", "#" + sb.toString());
  return Color.parseColor("#" + sb.toString());
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heighMode = MeasureSpec.getMode(heightMeasureSpec);
  int heighSize = MeasureSpec.getSize(heightMeasureSpec);
  setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthSize : getPaddingLeft() + getPaddingRight() + mBound.width(), heighMode == MeasureSpec.EXACTLY ? heighSize : getPaddingTop() + getPaddingBottom() + mBound.height());
 }
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  mPaint.setColor(mBgCplor);
  canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
  mPaint.setColor(mTextColor);
  canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);
 }
}

我们添加了一个点击事件,每一次点击View我都让它把生成的验证码和字体颜色以及字体背景颜色打印出来,如下所示:

您可能感兴趣的文章:Android实现合并生成分享图片功能android异步生成图片的示例代码Android栗子の图片验证码生成实例代码Android 实现图片生成卷角和圆角缩略图的方法Android实现用文字生成图片的示例代码Android 录制手机屏幕视频生成GIF图片实例详解Android仿简书长按文章生成图片效果Android生成带圆角的Bitmap图片android通过bitmap生成新图片关键性代码Android布局生成分享图片代码实例


--结束END--

本文标题: Android自定义View绘制随机生成图片验证码

本文链接: https://www.lsjlt.com/news/24049.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android自定义View绘制随机生成图片验证码
    本篇文章讲的是Android自定义View之随机生成图片验证码,开发中我们会经常需要随机生成图片验证码,但是这个是其次,主要还是想总结一些自定义View的开发过程以及一些需要注...
    99+
    2022-06-06
    view 图片 验证码 Android
  • Android自定义View实现随机验证码
    对于android开发来说自定义View还是一个比较重要的技能,所以在这里写一篇自定义View入门的文章,也是实现一个相对简单的随机产生验证码的功能: 自定义View主要也就...
    99+
    2022-06-06
    view 验证码 Android
  • Android自定义View编写随机验证码
    很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。先总...
    99+
    2022-06-06
    view 验证码 Android
  • Android自定义View实现随机数验证码
    目录前言效果自定义 View 分类步骤1.自定义属性2.添加构造方法3.在构造里获取自定义样式4.重写 onDraw 计算坐标绘制5.重写 onMeasure 测量宽高6.设置点击事...
    99+
    2022-11-13
  • Android通过自定义View实现随机验证码
    很多的Android入门程序猿来说对于Android自定义View,可能都是比较恐惧的,但是这又是高手进阶的必经之路,所有准备在自定义View上面花一些功夫,多写一些文章。 一...
    99+
    2022-06-06
    view 验证码 自定义view Android
  • Android怎么自定义View实现随机数验证码
    本篇内容介绍了“Android怎么自定义View实现随机数验证码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果自定义 View 分类简单...
    99+
    2023-07-02
  • Android自定义控件深入学习 Android生成随机验证码
    在上一篇的文章中介绍了自定义控件的属性,详情见《详解Android自定义控件属性TypedArray以及attrs》。那么在这基础上实现随机验证码生成,里面的代码是自定义控件以...
    99+
    2022-06-06
    学习 验证码 Android
  • java实现随机验证码图片生成
    本文实例为大家分享了java生成随机验证码图片的具体代码,供大家参考,具体内容如下 1.controller @GetMapping(value = "/getRan...
    99+
    2022-11-12
  • Android自定义view制作绚丽的验证码
    废话不多说了,先给大家展示下自定义view效果图,如果大家觉得还不错的话,请继续往下阅读。 怎么样,这种验证码是不是很常见呢,下面我们就自己动手实现这种效果,自己动手,丰衣足...
    99+
    2022-06-06
    view 验证码 Android
  • Python实现随机生成图片验证码详解
    使用python生成一个图片验证码,随机的,可以由于验证人机和别的啊,很方便很简单 导入模块 import random from PIL import Image,ImageFon...
    99+
    2022-11-13
  • java怎么实现随机验证码图片生成
    这篇文章主要介绍“java怎么实现随机验证码图片生成”,在日常操作中,相信很多人在java怎么实现随机验证码图片生成问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java怎么实现随机验证码图片生成”的疑惑有所...
    99+
    2023-06-25
  • 怎么用Python实现随机生成图片验证码
    本篇内容主要讲解“怎么用Python实现随机生成图片验证码”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么用Python实现随机生成图片验证码”吧!导入模块import random...
    99+
    2023-06-26
  • 怎么在Android中通过自定义View绘制一个四位数随机码
    怎么在Android中通过自定义View绘制一个四位数随机码?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。首先在res/values文件夹下建利attrs.xml文件,由于这次...
    99+
    2023-05-30
    android view
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作