自定义控件实现验证码



有注释,请看详情

新建valus/attr.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="titleText" format="string"/>
    <attr name="titleTextColor" format="color"/>
    <attr name="titleTextSize" format="dimension"/>
    <attr name="point_num" format="integer"/>
    <attr name="line_num" format="integer"/>
    <attr name="backgroundColor" format="color"/>
    <attr name="lineColor" format="color"/>
    <attr name="pointColor" format="color"/>
  
    
    
    <declare-styleable name="AuthNumView">
        <attr name="titleText"/>
        <attr name="titleTextColor"/>
        <attr name="titleTextSize"/>
        <attr name="backgroundColor" />
        <attr name="point_num" />
        <attr name="line_num" />
        <attr name="lineColor" />
        <attr name="pointColor" />
    </declare-styleable>
</resources>

package yu.cai.myview.widget;

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.Log;
import android.util.TypedValue;
import android.view.View;

import java.util.Random;

import yu.cai.myview.R;

/**
 * Created by 蔡宇奎 on 2017-7-4.
 */

public class AuthNumView extends View {
    private static final String TAG = "CustomTitleView";
    /**
     * 文本
     */
    private String mTitleText;
    /**
     * 文本的颜色
     */
    private int mTitleTextColor;
    /**
     * 文本的大小
     */
    private int mTitleTextSize;
    /**
     * 背景颜色设置
     */
    private int mBackgroundColor;
    /**
     * 点数设置
     */
    private int mPointNum;
    /**
     * 线数设置
     */
    private int mLineNum;

    private int mLineColor;

    private int mPointColor;

    // 点数设置
    private static final int DEFOULT_POINT_NUM = 100;
    // 线段数设置
    private static final int DEFOULT_LINE_NUM = 2;

    /**
     * 默认字体颜色
     */
    private static final int DEFOULT_TEXT_COLOR = Color.BLACK;

    /**
     * 默认线条颜色
     */
    private static final int DEFOULT_LINE_COLOR = Color.BLUE;
    /**
     * 默认圆点颜色
     */
    private static final int DEFOULT_POINT_COLOR =Color.BLUE;
    /**
     * 默认背景颜色
     */
    private static final int DEFAULT_BACKGROUND_COLOR = Color.YELLOW;

    /**
     * 固定字符串长4
     */
    private static final int DEFAULT_TEXT_NUM = 4;

    private Paint mPaint;
    private Rect mBound;
    private Random random = new Random();

    public AuthNumView(Context context) {
        this(context, null);
    }

    public AuthNumView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AuthNumView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        /**
         * 获得我们所定义的自定义样式属性
         */
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AuthNumView);
//        mTitleText = a.getString(R.styleable.AuthNumView_titleText);
        mTitleTextColor = a.getColor(R.styleable.AuthNumView_titleTextColor, DEFOULT_TEXT_COLOR);
        mTitleTextSize = a.getDimensionPixelSize(R.styleable.AuthNumView_titleTextSize, (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics()));
        mBackgroundColor = a.getColor(R.styleable.AuthNumView_backgroundColor,DEFAULT_BACKGROUND_COLOR);
        mLineNum = a.getInt(R.styleable.AuthNumView_line_num,DEFOULT_LINE_NUM);
        mPointNum = a.getInt(R.styleable.AuthNumView_point_num,DEFOULT_POINT_NUM);
        mLineColor = a.getColor(R.styleable.AuthNumView_lineColor,DEFOULT_LINE_COLOR);
        mPointColor = a.getColor(R.styleable.AuthNumView_pointColor,DEFOULT_POINT_COLOR);

        mTitleText = randomText();
        a.recycle();
        initPaint();
        initEvent();
    }

    private void initEvent() {
        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mTitleText = randomText();
//                invalidate();//只能在UI线程操作
                postInvalidate();//可以子线程中执行
            }
        });
    }

    private String randomText() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i <DEFAULT_TEXT_NUM; i++) {
            sb.append(random.nextInt(10));
        }
        return sb.toString();
    }

    private void initPaint() {
        mPaint = new Paint();
//        mPaint.setColor(mTitleTextColor);
        mPaint.setTextSize(mTitleTextSize);
        mPaint.setAntiAlias(true);
        mBound = new Rect();
        mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        Log.e(TAG,"widthMeasureSpec:"+widthMeasureSpec+",heightMeasureSpec:"+heightMeasureSpec);
        //属性设置为wrap_content时,,默认结果是match_content
        /**
         * MeasureSpec的specMode,一共三种类型:
         EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
         AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
         UNSPECIFIED:表示子布局想要多大就多大,很少使用
         */
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        Log.e(TAG, "widthMode: "+widthMode+",heightMode:"+heightMode );
        Log.e(TAG, "widthSize: "+widthSize+",heightSize:"+heightSize );//测量的宽高

        int width;
        int height ;
        if(widthMode==MeasureSpec.EXACTLY){//如果是固定宽高或者是match_content
            width = widthSize;
        }else{
            width = mBound.width() + getPaddingLeft() + getPaddingRight();
        }

        if(heightMode == MeasureSpec.EXACTLY){
            height = heightSize;
        }else {
            height = mBound.height()+getPaddingBottom()+getPaddingTop();
        }
        Log.e(TAG,"width:"+width+",height"+height);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        /**
         * 背景
         */
        mPaint.setColor(mBackgroundColor);
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);
        /**
         * 写字
         */
        mPaint.setColor(mTitleTextColor);
        canvas.drawText(mTitleText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);

        /**
         *  画线
         */
        //划线
        mPaint.setColor(mLineColor);
        int [] line;
        for(int i = 0; i < mLineNum; i ++)
        {
            //设置线宽
            mPaint.setStrokeWidth(5);
            line = getLine(getMeasuredHeight(), getMeasuredWidth());
            canvas.drawLine(line[0], line[1], line[2], line[3], mPaint);
        }
        /**
         * 画点
         */
        mPaint.setColor(mPointColor);
        // 绘制小圆点
        int [] point;
        int randomInt;
        for(int i = 0; i < mPointNum; i ++)
        {
            //随机获取点的大小
            randomInt = random.nextInt(10);
            point = getPoint(getMeasuredHeight(), getMeasuredWidth());
            canvas.drawCircle(point[0], point[1], randomInt, mPaint);
        }


    }

    // 随机产生点的圆心点坐标
    private 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;
    }

    //随机产生划线的起始点坐标和结束点坐标
    private 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;
    }

    //获取验证码
    public String getAuthCode() {
        return mTitleText;
    }
}
    <yu.cai.myview.widget.AuthNumView
        android:id="@+id/authNumView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="20dp"
        android:layout_centerInParent="true"
        app:pointColor="@android:color/holo_green_dark"
        app:lineColor="@android:color/holo_red_dark"
        app:backgroundColor="@android:color/holo_orange_light"
        app:titleTextSize="25sp"
        app:line_num="5"
        />





猜你喜欢

转载自blog.csdn.net/cai784921129/article/details/74356132