自定义view之验证码

自定义view之验证码TextView

效果图如下
效果图

package com.felix.client.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.os.Handler;
import android.os.Message;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;

import com.felix.client.R;


/**
 * Created by fangxin on 2020/4/16.
 */

public class TextViewWithIdentifyingCode extends AppCompatTextView {
    private String textTitle;
    private int textColor;
    private int textSize;
    private Paint paint;
    private Rect rect;
    private int bgColor = -1;
    private int mSum = -1;
    private OnChangeListener mOnChangeListener;
    private static final int DEFAULT_NAM = 4;
    private String mRes = "2020";

    private static String[] types = new String[]{"num", "lower", "higher", ""};
    private static char[] nums = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    private static char[] lowers = new char[]{'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 void setTextLength(int sum) {
        this.mSum = sum;
    }

    public void setTextOnChangedLisenter(OnChangeListener onChangeListener) {
        if (mSum == -1) {
            mSum = DEFAULT_NAM;
        }
        this.mOnChangeListener = onChangeListener;
        refreshText();
    }

    public void refreshText() {
        if (mSum == -1) {
            mSum = DEFAULT_NAM;
        }
        random(mSum);
        setTextTitle(mRes);
        if (mOnChangeListener != null) {
            mOnChangeListener.onChanged(mRes);
        }
    }

    private void setTextTitle(String textTitle) {
        this.textTitle = textTitle;
        invalidate();
        requestLayout();
    }

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

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

    public TextViewWithIdentifyingCode(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TextViewWithIdentifyingCode, defStyleAttr, 0);
        int length = array.length();
        for (int i = 0; i < length; i++) {
            int attr = array.getIndex(i);
            if (attr == R.styleable.TextViewWithIdentifyingCode_felix_text_color) {
                textColor = array.getColor(attr, Color.BLUE);
            } else if (attr == R.styleable.TextViewWithIdentifyingCode_felix_text_size) {
                textSize = array.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()));
            } else if (attr == R.styleable.TextViewWithIdentifyingCode_felix_text_title) {
                textTitle = array.getString(attr);
                random(4);
                textTitle = mRes;
            } else if (attr == R.styleable.TextViewWithIdentifyingCode_felix_background_color) {
                bgColor = array.getColor(attr, Color.BLUE);
            }
        }
        array.recycle();
        paint = new Paint();
        paint.setTextSize(textSize);
        paint.setColor(textColor);
        // 创建一个矩形
        rect = new Rect();
        /*
          @param text  String to measure and return its bounds 要测量的文字
         * @param start Index of the first char in the string to measure    测量的起始位置
         * @param end   1 past the last char in the string measure  测量的最后一个字符串的位置
         * @param bounds Returns the unioned bounds of all the text. Must be    rect对象
         *               allocated by the caller.
         */
        paint.getTextBounds(textTitle, 0, textTitle.length(), rect);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.setColor(bgColor == -1 ? Color.GREEN : bgColor);
        //设置矩形长和高
        //drawRect(float left, float top, float right, float bottom,Paint paint)
        canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), paint);
        paint.setColor(textColor);
//        canvas.drawText(textTitle, getWidth() / 2 - rect.width() / 2, getHeight() / 2 + rect.height() / 2, paint);
        canvas.drawText(textTitle, getPaddingLeft(), getHeight() / 2 + rect.height() / 2, paint);


        // 获取到自定义的view宽高
        final int height = getHeight();
        final int width = getWidth();
        // 绘制小圆点
        int[] point;
        for (int i = 0; i < 50; i++) {
            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], 1, paint);
        }

        int[] line;
        for (int i = 0; i < 100; i++) {
            line = getLine(height, width);
            /**
             * startX:起始端点的X坐标。
             *startY:起始端点的Y坐标。
             *stopX:终止端点的X坐标。
             *stopY:终止端点的Y坐标。
             *paint:绘制直线所使用的画笔。
             */
            canvas.drawLine(line[0], line[1], line[2], line[3], paint);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获取到宽高的测量模式以及测量值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        Log.e("tag", "" + widthMode + widthSize);

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        Log.e("tag", "" + heightMode + heightSize);
        int width;
        int height;
        // 宽如果是精确测量
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            paint.setTextSize(textSize);
            paint.getTextBounds(textTitle, 0, textTitle.length(), rect);
            int textWidth = rect.width();
            int measureWidth = getPaddingLeft() + textWidth + getPaddingRight();
            width = measureWidth;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            paint.setTextSize(textSize);
            paint.getTextBounds(textTitle, 0, textTitle.length(), rect);
            float textHeight = rect.height();
            int measureHeight = (int) (getPaddingTop() + textHeight + getPaddingBottom());
            height = measureHeight;
        }

        // 重新设置空间的宽高
        setMeasuredDimension(width, height);
    }

    public 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;
    }

    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 void random(int num) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < num; i++) {
            String type = types[(int) (Math.random() * types.length)];
            if (type.equals(types[0])) {
                res.append(nums[(int) (Math.random() * nums.length)]);
            } else if (type.equals(types[1])) {
                res.append(lowers[(int) (Math.random() * lowers.length)]);
            } else if (type.equals(types[2])) {
                res.append((char) (lowers[(int) (Math.random() * lowers.length)] - 32));
            } else {
                res.append(nums[(int) (Math.random() * nums.length)]);
            }
        }
        mRes = res.toString();
    }

    public interface OnChangeListener {
        void onChanged(String s);
    }
}

使用控件

<com.felix.client.widget.TextViewWithIdentifyingCode
    android:id="@+id/tv_test"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:paddingLeft="20dp"
    android:text="Hello World!"
    app:background_color="#bebebe"
    app:text_color="#000000"
    app:text_size="60sp"
    app:text_title="WWWW" />

attrs文件

<declare-styleable name="TextViewWithIdentifyingCode">
    <attr name="text_title" format="string" />
    <attr name="text_color" format="color" />
    <attr name="text_size" format="dimension" />
    <attr name="background_color" format="color" />
</declare-styleable>

MainActivity中使用该控件

mTvTest.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        mTvTest.setTextTileForRandom(4, new TextViewWithIdentifyingCode.OnChangeListener() {
            @Override
            public void onChanged(String s) {
                mEtTest.setText(s);
            }
        });
    }
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值