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

本文详细介绍了如何在Android中自定义一个View来实现验证码功能,包括定义属性、初始化、重写onMeasure和onDraw方法。通过实例代码展示了如何生成随机背景颜色、文字颜色、干扰点和曲线,从而增强验证码的复杂性和安全性。
摘要由CSDN通过智能技术生成

对于android开发来说自定义View还是一个比较重要的技能,所以在这里写一篇自定义View入门的文章,也是实现一个相对简单的随机产生验证码的功能:

自定义View主要也就分为几步 1.自定义View的属性

2.在我们的自定义的布局中获取自定义属性

3.重写onMesure方法

4.重写onDraw方法

好现在我们就一步一步的来,首先创建我们的View属性

在valuse目录下创建一个attrs.xml的文件,然后:

我们总共定义了三个属性,一个是颜色,内容,大小

然后我们去建立我们的自定义类

public class VerificationCodeView extends View {

/**

* 文本

*/

private String mTitleText;

/**

* 文本的颜色

*/

private int mTextColor;

/**

* 文本的大小

*/

private int mTextSize;

/**

* 绘制时控制文本绘制的范围

*/

private Rect mBound;

/**

* 初始化画笔

*/

private Paint mTextPaint;

private Paint mPointPaint;

private Paint mPathPaint;

/**

* 干扰点坐标的集合

*/

private ArrayList mPoints = new ArrayList();

/**

* 绘制贝塞尔曲线的路径集合

*/

private ArrayList mPaths = new ArrayList();

public VerificationCodeView(Context context) {

this(context, null);

}

public VerificationCodeView(Context context, AttributeSet attributeSet) {

this(context, attributeSet, 0);

}

public VerificationCodeView(Context context, AttributeSet attributeSet, int defStyle) {

super(context, attributeSet, defStyle);

TypedArray typedArray = context.getTheme().obtainStyledAttributes(attributeSet, R.styleable.VerificationCodeView, defStyle, 0);

int size = typedArray.getIndexCount();

for (int i = 0; i < size; i++) {

int content = typedArray.getIndex(i);

switch (content) {

case R.styleable.VerificationCodeView_textContent:

mTitleText = typedArray.getString(content);

break;

case R.styleable.VerificationCodeView_textColor:

mTextColor = typedArray.getColor(content, Color.BLACK);

break;

case R.styleable.VerificationCodeView_textSize:

// 默认设置为16sp,TypeValue也可以把sp转化为px

mTextSize = typedArray.getDimensionPixelSize(content, (int) TypedValue.applyDimension(

TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));

break;

}

}

typedArray.recycle();

//设置点击事件变换数字

this.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

mTitleText = randomText();

postInvalidate();

}

});

}

/**

* EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

* AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

* UNSPECIFIED:表示子布局想要多大就多大,很少使用

*

* @param widthMeasureSpec

* @param heightMeasureSpec

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

//用来设置要画的布局的大小

if (widthMode != MeasureSpec.EXACTLY) {

widthSize = (int) (getPaddingLeft() + mBound.width() + getPaddingRight());

}

if (heightMode != MeasureSpec.EXACTLY) {

heightSize = (int) (getPaddingTop() + mBound.height() + getPaddingBottom());

}

setMeasuredDimension(widthSize, heightSize);

}

@Override

protected void onDraw(Canvas canvas) {

//生成随机的背景颜色

mTextPaint.setColor(Color.YELLOW);

canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mTextPaint);

//生成随机的文字颜色

mTextPaint.setColor(mTextColor);

//将文字画在布局的中间

canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mTextPaint);

}

/**

* 生成随机的四位数字验证码

*

* @return

*/

private String randomText() {

Random random = new Random();

Set set = new HashSet();

while (set.size() < 4) {

int randomInt = random.nextInt(10);

set.add(randomInt);

}

StringBuffer sb = new StringBuffer();

for (Integer i : set) {

sb.append("" + i);

}

return sb.toString();

}

}

以上代码就是自定义的类,继承了View他有三个构造方法,我们要获取它的属性,所以一定要走第三个,但是默认是第二个,所以我们要在每一个里面调用第三个,以确保做了初始化工作 注意调用的时候用的是this的构造方法,而不是super

当我们的这个类出来之后,后面的就很简单了

xmlns:verification="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:gravity="center"

>

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:paddingTop="10dp"

android:paddingBottom="10dp"

android:paddingLeft="10dp"

android:paddingRight="10dp"

verification:textContent="3712"

verification:textColor="#ff0000"

verification:textSize="40sp" />

在布局里面应用它就可以了, xmlns:verification=”http://schemas.android.com/apk/res-auto”是必须要的,要不找不到自定义的属性。

好了到这为止就实现了最简单的

b98cd18d80c70466b244df5f17cae127.png

接下来我们就是实现绘制一些散点和曲线,修改我们的自定义类的onDraw()方法

@Override

protected void onDraw(Canvas canvas) {

initData();

Random mRandom = new Random();

//生成随机的背景颜色

mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);

canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mTextPaint);

//生成随机的文字颜色

mTextPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);

//将文字画在布局的中间

canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mTextPaint);

// 产生干扰效果1 -- 干扰点

for (PointF pointF : mPoints) {

mPointPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);

canvas.drawPoint(pointF.x, pointF.y, mPointPaint);

}

// 产生干扰效果2 -- 干扰线

for (Path path : mPaths) {

mPathPaint.setARGB(255, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20, mRandom.nextInt(200) + 20);

canvas.drawPath(path, mPathPaint);

}

private void initData() {

Random mRandom = new Random();

// 获取控件的宽和高,此时已经测量完成

int mHeight = getHeight();

int mWidth = getWidth();

mPoints.clear();

// 生成干扰点坐标

for (int i = 0; i < 150; i++) {

PointF pointF = new PointF(mRandom.nextInt(mWidth) + 10, mRandom.nextInt(mHeight) + 10);

mPoints.add(pointF);

}

mPaths.clear();

// 生成干扰线坐标

for (int i = 0; i < 2; i++) {

Path path = new Path();

int startX = mRandom.nextInt(mWidth / 3) + 10;

int startY = mRandom.nextInt(mHeight / 3) + 10;

int endX = mRandom.nextInt(mWidth / 2) + mWidth / 2 - 10;

int endY = mRandom.nextInt(mHeight / 2) + mHeight / 2 - 10;

path.moveTo(startX, startY);

path.quadTo(Math.abs(endX - startX) / 2, Math.abs(endY - startY) / 2, endX, endY);

mPaths.add(path);

}

}

private void init() {

// 初始化文字画笔

/**

* 获得绘制文本的宽和高

*/

mTextPaint = new Paint();

mTextPaint.setTextSize(mTextSize);

mBound = new Rect();

//获取到的存在mBound里面

mTextPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);

// 初始化干扰点画笔

mPointPaint = new Paint();

mPointPaint.setStrokeWidth(6);

mPointPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形

// 初始化干扰线画笔

mPathPaint = new Paint();

mPathPaint.setStrokeWidth(5);

mPathPaint.setColor(Color.GRAY);

mPathPaint.setStyle(Paint.Style.STROKE); // 设置画笔为空心

mPathPaint.setStrokeCap(Paint.Cap.ROUND); // 设置断点处为圆形

}

init()方法请自行加在构造方法里面

OK到这为止就完成了,以后我们用到只要移植就可以了,怎么样,也很简单吧

c01d3a9cd221c042488b0cc7afeed786.png

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值