Android自定义View入门之简单验证码控件

自定义View实现步骤:
1、自定义View的属性。
2、在View的构造方法中获得我们自定义的属性。
3、重写onMesure(非必须)。
【Android自定义View入门之简单验证码控件】4、重写onDraw。
新建attrs.xml













布局中

xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.cjf.customview.MainActivity">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:titleText="4396"
android:padding="10dp"
app:titleTextColor="#ff0000"
app:titleTextSize="40sp"
/>

具体实现代码:
package com.cjf.customview.cutomtitleView;
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.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.cjf.customview.R;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
_/**

  • Created by jackchenfeng on 2017/4/21.
    */
_public class CustomTitleViewextends View {
privateString mTitleText; //文本
private intmTitleColor; //文字颜色
private intmTitleSize; //文字大小
_/**
  • 绘制时控制文本绘制的范围
    */
    _privateRect mBound;
    private PaintmPaint;
public CustomTitleView(Context context) {
this(context, null);
}
publicCustomTitleView(Context context,@Nullable AttributeSet attrs) {
this(context,attrs,0);
}
publicCustomTitleView(Context context,@Nullable AttributeSet attrs, intdefStyleAttr) {
super(context,attrs,defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,R.styleable.CustomTitleView,defStyleAttr,0);
int n = a.getIndexCount();
for (inti = 0; i < n; i++) {
intattr = a.getIndex(i);
switch (attr) {
caseR.styleable.CustomTitleView_titleText:
mTitleText= a.getString(attr);
break;
case R.styleable.CustomTitleView_titleTextColor:
mTitleColor= a.getColor(attr,Color.BLACK);
break;
case R.styleable.CustomTitleView_titleTextSize:
mTitleSize= (int) a.getDimension(attr,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
break;
}
}
a.recycle();
mPaint= newPaint();
mPaint.setTextSize(mTitleSize);
mBound= newRect();
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
this.setOnClickListener(newOnClickListener() {
@Override
public voidonClick(View v) {
mTitleText= randomText();
postInvalidate();
}
});
}
privateString randomText() {
Random random = newRandom();
Set set =new HashSet();
while (set.size() <4) {
intrandomInt = random.nextInt(10);
set.add(randomInt);
}
StringBuffer sb = newStringBuffer();
for (Integer i : set) {
sb.append(""+ i);
}
returnsb.toString();
}
@Override
protected voidonMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
_/**
  • 重写之前先了解MeasureSpec的specMode,一共三种类型:
    EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
    AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
    UNSPECIFIED:表示子布局想要多大就多大,很少使用
    */
    _intwidthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heghtSize = MeasureSpec.getSize(heightMeasureSpec);
    int width;
    int height;
    if (widthMode == MeasureSpec.EXACTLY) {
    width = widthSize;
    }else {
    mPaint.setTextSize(mTitleSize);
    mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
    float textWidth =mBound.width();
    int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());
    width = desired;
    }
if(heightMode == MeasureSpec.EXACTLY) {
height = heghtSize;
}else {
mPaint.setTextSize(mTitleSize);
mPaint.getTextBounds(mTitleText,0,mTitleText.length(),mBound);
float textHeight =mBound.height();
int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());
height = desired;
}
setMeasuredDimension(width,height);
}
@Override
protected voidonDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.YELLOW);
canvas.drawRect(0,0,getMeasuredWidth(),getMeasuredHeight(),mPaint);
mPaint.setColor(mTitleColor);
//getwidth()获得整个view的宽度
canvas.drawText(mTitleText,getWidth() / 2- mBound.width() /2,getHeight() / 2+ mBound.height() /2,mPaint);
final int height = getHeight();
final int width = getWidth();
int[] point;
Random random =new Random();
for (inti = 0; i < 50; i++) {
intranColor = 0xff000000| random.nextInt(0x00ffffff); //随机颜色
mPaint.setColor(ranColor);
point = getPoint(height,width);
_/**
  • drawCircle (float cx, float cy, float radius, Paint paint)
  • float cx:圆心的x坐标。
  • float cy:圆心的y坐标。
  • float radius:圆的半径。
  • Paint paint:绘制时所使用的画笔。
    */
    _canvas.drawCircle(point[0],point[1],3,mPaint);
    }
int[] line;
for (inti = 0; i < 5; i++) {
intranColor = 0xff000000| random.nextInt(0x00ffffff); //随机颜色
mPaint.setColor(ranColor);
line = getLine(height,width);
_/**
  • startX:起始端点的X坐标。
    *startY:起始端点的Y坐标。
    *stopX:终止端点的X坐标。
    *stopY:终止端点的Y坐标。
    *paint:绘制直线所使用的画笔。
    */
    _canvas.drawLine(line[0],line[1],line[2],line[3],mPaint);
    }
}
private int[]getLine(intheight, intwidth) {
int[] tempCheckNum = {0,0,0,0};
for (inti = 0; i < 4; i += 2) {
tempCheckNum[i] = (int) (Math.random() * width);
tempCheckNum[i +1] = (int) (Math.random() * height);
}
returntempCheckNum;
}
private int[]getPoint(intheight, intwidth) {
int[] tempCheckNum = {0,0,0,0};
tempCheckNum[0] = (int) (Math.random() * width);
tempCheckNum[1] = (int) (Math.random() * height);
return tempCheckNum;
}
}
效果图:点击可随机产生数字
Android自定义View入门之简单验证码控件
文章图片

    推荐阅读