Android自定义控件之验证码输入框

先上效果图

attrs

  <!--验证码输入框-->
    <declare-styleable name="VerificationCodeView">
        <attr name="codeLength" format="integer" />
        <attr name="beforeLineColor" format="color" />
        <attr name="currentLineColor" format="color" />
        <attr name="bgHeightWidth" format="dimension" />
        <attr name="bgBorderRadius" format="dimension" />
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
        <attr name="space" format="dimension" />
        <attr name="lineWidth" format="dimension" />
        <attr name="paddingStart" format="dimension" />
        <attr name="paddingEnd" format="dimension" />
        <attr name="paddingTop" format="dimension" />
        <attr name="paddingBottom" format="dimension" />
    </declare-styleable>

java文件

/**
 * 自定义输入验证码控件
 *
 * @author: whr
 * @date: 2021/01/21
 */
public class VerificationCodeView extends androidx.appcompat.widget.AppCompatEditText {
    /**
     * 间隔
     */
    private float space = 45;
    /**
     * 验证码长度
     */
    private int codeLength = 6;
    /**
     * 未输入下划线颜色
     */
    private int beforeLineColor = Color.WHITE;
    /**
     * 当前输入下划线颜色
     */
    private int currentLineColor = Color.WHITE;
    /**
     * 文字颜色
     */
    private int textColor = Color.WHITE;

    /**
     * 文本字体大小
     */
    private float textSize = 70f;

    /**
     * 验证码框下划线宽度
     */
    private int lineHeight = 4;
    /**
     * 已输入背景框圆角
     */
    private float bgBorderRadius = 24;
    /**
     * 已输入背景框高度
     */
    private float bgBorderHeight = 50;
    /**
     * 文本画笔
     */
    private Paint mTextPaint;
    /**
     * 背景框画笔
     */
    private Paint mBorderPaint;
    /**
     * 输入的密码长度
     */
    private int mInputLength;
    /**
     * 输入结束监听
     */
    private OnInputFinishListener mOnInputFinishListener;
    /**
     * 左右间距
     */
    private float paddingStart, paddingEnd, paddingTop, paddingBottom = 0;
    private String text;

    /**
     * 构造方法
     *
     * @param context
     * @param attrs
     */
    public VerificationCodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView);
        codeLength = array.getInteger(R.styleable.VerificationCodeView_codeLength, codeLength);
        beforeLineColor = array.getInteger(R.styleable.VerificationCodeView_beforeLineColor, beforeLineColor);
        currentLineColor = array.getInteger(R.styleable.VerificationCodeView_currentLineColor, currentLineColor);
        bgBorderHeight = array.getDimension(R.styleable.VerificationCodeView_bgHeightWidth, bgBorderHeight);
        bgBorderRadius = array.getDimension(R.styleable.VerificationCodeView_bgBorderRadius, bgBorderRadius);
        space = array.getDimension(R.styleable.VerificationCodeView_space, space);
        lineHeight = (int) array.getDimension(R.styleable.VerificationCodeView_lineHeight, lineHeight);

        textSize = array.getDimension(R.styleable.VerificationCodeView_textSize, textSize);
        textColor = array.getInteger(R.styleable.VerificationCodeView_textColor, textColor);

        paddingStart = array.getDimension(R.styleable.VerificationCodeView_paddingStart, paddingStart);
        paddingEnd = array.getDimension(R.styleable.VerificationCodeView_paddingEnd, paddingEnd);
        paddingTop = array.getDimension(R.styleable.VerificationCodeView_paddingTop, paddingTop);
        paddingBottom = array.getDimension(R.styleable.VerificationCodeView_paddingBottom, paddingBottom);

        // 初始化文字画笔
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setColor(textColor);
        mTextPaint.setTextSize(textSize);

        // 初始化下划线
        mBorderPaint = new Paint();
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setColor(beforeLineColor);
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setStrokeWidth(lineHeight);
        mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //获取控件宽高的显示模式
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        //获取宽高的尺寸值 固定值的宽度
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        //设置宽高默认为建议的最小宽高
        int width;
        int height;
        // MeasureSpec父布局传递给后代的布局要求 包含 确定大小和三种模式
        // EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
        // AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
        // UNSPECIFIED:表示子布局想要多大就多大,很少使用
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = widthSize;
        }

        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = (int) (bgBorderHeight + paddingTop + paddingBottom + lineHeight * 2);
        }
        //设置测量的宽高
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 这三行代码非常关键,大家可以注释点在看看效果
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        canvas.drawRect(0, 0, getWidth(), getHeight(), paint);

        // 计算每个密码框宽度
        int rectWidth = (int) ((getWidth() - space * (codeLength - 1) - paddingStart - paddingEnd) / codeLength);
        int bottom = (int) (paddingStart + bgBorderHeight);

        // 绘制背景
        for (int i = 0; i < codeLength; i++) {
            int left = (int) (paddingStart + lineHeight + (rectWidth + space) * i);
            int right = (int) (left + rectWidth - paddingEnd - lineHeight);
            int top = (int) paddingTop + lineHeight;

            if (i < mInputLength) {
                //绘制背景色
                mBorderPaint.setColor(currentLineColor);
                mBorderPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                RectF rectF = new RectF(left, top, right, bottom);
                canvas.drawRoundRect(rectF, bgBorderRadius, bgBorderRadius, mBorderPaint);

                //绘制文本
                int cx = left + rectWidth / 2;
                int cy = (bottom / 2 + WindowUtils.px2dp(textSize));
                String[] c = text.split("");
                mTextPaint.setTextAlign(Paint.Align.CENTER);
                canvas.drawText(c[i], cx, cy, mTextPaint);
            } else {
                if (i == mInputLength) {
                    mBorderPaint.setColor(currentLineColor);
                } else {
                    mBorderPaint.setColor(beforeLineColor);
                }
                canvas.drawLine(left, bottom, right, bottom, mBorderPaint);
            }
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        this.mInputLength = text.toString().length();
        if (mInputLength <= codeLength) {
            this.text = text.toString();
            invalidate();
            if (mInputLength == codeLength && mOnInputFinishListener != null) {
                mOnInputFinishListener.onInputFinish(text.toString());
            }
        }
    }

    public interface OnInputFinishListener {
        /**
         * 密码输入结束监听
         *
         * @param password
         */
        void onInputFinish(String password);
    }

    /**
     * 设置输入完成监听
     *
     * @param onInputFinishListener
     */
    public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
        this.mOnInputFinishListener = onInputFinishListener;
    }
}

使用

 <com.whr.demo.mydemolist.ui.view.VerificationCodeView
        android:id="@+id/ed_code"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/transparent"
        android:cursorVisible="false"
        android:enabled="true"
        android:focusable="true"
        android:inputType="number"
        android:maxLength="6"
        app:beforeLineColor="#f5f5f5"
        app:bgBorderRadius="30dp"
        app:bgHeightWidth="48dp"
        app:codeLength="6"
        app:currentLineColor="#fd4f00"
        app:lineHeight="2dp"
        app:space="15dp"
        app:textColor="#ffffff"
        app:textSize="66dp" />

属性说明:

  1. codeLength:验证码长度
    
  2. beforeLineColor:未输入框下划线颜色
  3. currentLineColor:当前输入下划线颜色
  4. bgHeightWidth:已输入框背景色
  5. bgBorderRadius:已输入框圆角大小
  6. textColor:文本颜色
  7. textSize:文本大小
  8. space:文本框间距
  9. lineHeight:下划线高度
    
  10. paddingStart:已输入文本距边框start间距
  11. paddingEnd:已输入文本距边框end间距
  12. paddingTop:已输入文本距边框top间距
  13. paddingBottom:已输入文本距边框bottom间距
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值