Android自定义控件:通用验证码输入框

效果图

话不多说先上效果图,可以先先看看是不是自己想要的

输入效果
未输入效果

闲聊

闲来无事优化项目时,发现原来的验证码输入框,可扩展性不高,就拿来优化了一下,说说我开始的的思路吧,最开始是想用自定义View实现的,但是发现各种画矩,太烦人了,最后采用的组合控件的形式,Android有现成的控件,用来组合组合就能用,为什么不用呢,真香~

源码

xml ITEM 布局文件(view_auth_code_input_item.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/number_tv"
        style="@style/TextStyleMain"
        android:layout_width="match_parent"
        android:layout_height="0mm"
        android:layout_weight="1"
        android:maxLength="1"
        android:text="0"
        android:textSize="72mm" />

    <View
        android:id="@+id/split_v"
        android:layout_width="match_parent"
        android:layout_height="1mm"
        android:background="@color/colorMain" />

</LinearLayout>

attrs 自定义属性(attrs.xml)

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- 自定义验证码输入框 属性 -->
    <declare-styleable name="AuthCodeInputView">
        <!-- 当前输入位分割线颜色 -->
        <attr name="currentSplitLineColor"
            format="reference|color" />
        <!-- 其他输入位分割线颜色 -->
        <attr name="otherSplitLineColor"
            format="reference|color" />
        <!-- 分割线高度 -->
        <attr name="splitLineHeight"
            format="dimension" />
        <!-- 验证码位数 -->
        <attr name="digit"
            format="integer" />
        <!-- 单个验证码宽度 -->
        <attr name="singleCaptchaWidth"
            format="dimension" />
        <!-- 验证码当前输入位字体颜色 -->
        <attr name="currentTextColor"
            format="reference|color" />
        <!-- 验证码当前输入位字体大小 -->
        <attr name="currentTextSize"
            format="dimension" />
        <!-- 验证码其他输入位字体颜色 -->
        <attr name="otherTextColor"
            format="reference|color" />
        <!-- 验证码其它输入位字体大小 -->
        <attr name="otherTextSize"
            format="dimension" />
        <!-- 默认颜色 -->
        <attr name="defaultColor"
            format="reference|color" />
        <!-- 默认字体大小 -->
        <attr name="defaultTextSize"
            format="dimension" />
        <!-- 默认间距 -->
        <attr name="defaultSpacing"
            format="dimension" />
    </declare-styleable>

</resources>

组合控件(AuthCodeInputView.java)


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.ColorInt;
import androidx.annotation.RequiresApi;

/**
 * <pre>
 *     <b>author</b>    :BraveTou
 *     <b>blog</b>      :https://blog.csdn.net/bravetou
 *     <b>time</b>      :2020/9/4 16:43
 *     <b>desc</b>      :<pre>
 *         自定义验证码输入框
 *     </pre>
 * </pre>
 */
public class AuthCodeInputView extends LinearLayout {
    // <!-- 默认间距 -->
    private int mDefaultSpacing = 16;
    // <!-- 默认颜色 -->
    @ColorInt
    private int mDefaultColor = Color.BLACK;
    // <!-- 默认字体大小 -->
    private int mDefaultTextSize = 36;
    // <!-- 当前输入位分割线颜色 -->
    @ColorInt
    private int mCurrentSplitLineColor = mDefaultColor;
    // <!-- 其他输入位分割线颜色 -->
    @ColorInt
    private int mOtherSplitLineColor = mDefaultColor;
    // <!-- 分割线高度 -->
    private int mSplitLineHeight = 1;
    // <!-- 验证码位数 -->
    private int mDigit = 4;
    // <!-- 单个验证码宽度 -->
    private int mSingleCaptchaWidth = 100;
    // <!-- 验证码当前输入位字体颜色 -->
    @ColorInt
    private int mCurrentTextColor = mDefaultColor;
    // <!-- 验证码当前输入位字体大小 -->
    private int mCurrentTextSize = mDefaultTextSize;
    // <!-- 验证码其他输入位字体颜色 -->
    @ColorInt
    private int mOtherTextColor = mDefaultColor;
    // <!-- 验证码其它输入位字体大小 -->
    private int mOtherTextSize = mDefaultTextSize;

    // 记录当前输入文本
    private String mText = "";

    public AuthCodeInputView(Context context) {
        super(context);
        init(context, null);
    }

    public AuthCodeInputView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public AuthCodeInputView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public AuthCodeInputView(Context context, AttributeSet attrs, int defStyleAttr,
                             int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    // 初始化
    private void init(Context context, AttributeSet attrs) {
        setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER);
        if (getChildCount() > 0) {
            removeAllViews();
        }
        initAttrs(context, attrs);
        if (mDigit <= 0) {
            return;
        }
        for (int i = 0; i < mDigit; i++) {
            // 实例化 ITEM 组件
            View child = LayoutInflater.from(context).inflate(
                    R.layout.view_auth_code_input_item, this, false);
            LayoutParams lp = new LayoutParams(mSingleCaptchaWidth,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            if (i != 0) {
                lp.leftMargin = mDefaultSpacing;
            }
            child.setLayoutParams(lp);
            setViewAttrs(child, null, false);
            // 分割线高度只在初始化时设置一次
            View mSplitV = child.findViewById(R.id.split_v);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT, mSplitLineHeight);
            mSplitV.setLayoutParams(params);
            addView(child);
        }
    }

    // 设置(未)选中属性
    private void setViewAttrs(View child, String text, boolean isSelected) {
        TextView mNumberTv = child.findViewById(R.id.number_tv);
        View mSplitV = child.findViewById(R.id.split_v);
        if (isSelected) {
            mNumberTv.setTextColor(mCurrentTextColor);
            mNumberTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mCurrentTextSize);
            mSplitV.setBackgroundColor(mCurrentSplitLineColor);
        } else {
            mNumberTv.setTextColor(mOtherTextColor);
            mNumberTv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mOtherTextSize);
            mSplitV.setBackgroundColor(mOtherSplitLineColor);
        }
        mNumberTv.setText(TextUtils.isEmpty(text) ? "" : text);
    }

    // 初始化属性
    private void initAttrs(Context context, AttributeSet attrs) {
        if (null != attrs) {
            // AttributeSet 属性值的索引
            TypedArray o = context.obtainStyledAttributes(attrs, R.styleable.AuthCodeInputView);
            // 默认间距
            mDefaultSpacing = (int) o.getDimension(R.styleable.AuthCodeInputView_defaultSpacing,
                    16f);
            // 获取默认颜色
            mDefaultColor = o.getColor(R.styleable.AuthCodeInputView_defaultColor, Color.BLACK);
            // 获取默认字体大小
            mDefaultTextSize = (int) o.getDimension(R.styleable.AuthCodeInputView_defaultTextSize
                    , 36f);
            // 输入位分割线颜色
            mCurrentSplitLineColor =
                    o.getColor(R.styleable.AuthCodeInputView_currentSplitLineColor, mDefaultColor);
            // 其他输入位分割线颜色
            mOtherSplitLineColor = o.getColor(R.styleable.AuthCodeInputView_otherSplitLineColor,
                    mDefaultColor);
            // 分割线高度
            mSplitLineHeight = (int) o.getDimension(R.styleable.AuthCodeInputView_splitLineHeight
                    , 1f);
            mSplitLineHeight = mSplitLineHeight <= 1 ? 1 : mSplitLineHeight;
            // 验证码位数
            mDigit = o.getInteger(R.styleable.AuthCodeInputView_digit, 4);
            // 单个验证码宽度
            mSingleCaptchaWidth =
                    (int) o.getDimension(R.styleable.AuthCodeInputView_singleCaptchaWidth, 100f);
            // 验证码当前输入位字体颜色
            mCurrentTextColor = o.getColor(R.styleable.AuthCodeInputView_currentTextColor,
                    mDefaultColor);
            // 验证码当前输入位字体大小
            mCurrentTextSize = (int) o.getDimension(R.styleable.AuthCodeInputView_currentTextSize
                    , mDefaultTextSize);
            // 验证码其他输入位字体颜色
            mOtherTextColor = o.getColor(R.styleable.AuthCodeInputView_otherTextColor,
                    mDefaultColor);
            // 验证码其它输入位字体大小
            mOtherTextSize = (int) o.getDimension(R.styleable.AuthCodeInputView_otherTextSize,
                    mDefaultTextSize);
            // 回收资源
            o.recycle();
        }
    }

    // 追加文本
    public void addText(String text) {
        text = TextUtils.isEmpty(text) ? "" : text;
        setText(mText + text);
    }

    // 删除文本
    public void delText() {
        int count = TextUtils.isEmpty(mText) ? 0 : mText.length();
        if (count > 0) {
            setText(mText.substring(0, count - 1));
        } else {
            setText("");
        }
    }

    // 设置文本
    public void setText(String text) {
        text = text.trim();
        int length = TextUtils.isEmpty(text) ? 0 : text.length();
        if (length > mDigit) {
            this.mText = text.substring(0, mDigit);
            length = mDigit;
        } else {
            this.mText = length > 0 ? text : "";
        }
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (i + 1 < length) {
                setViewAttrs(child, String.valueOf(text.charAt(i)), false);
            } else if (i + 1 == length) {
                setViewAttrs(child, String.valueOf(text.charAt(i)), true);
            } else {
                setViewAttrs(child, null, false);
            }
        }
    }

    // 获取文本
    public String getText() {
        return mText;
    }
}

至于效果图下面那个安全键盘源码就太多了,我就不多了的,我这边是组合控件实现的,超简单,over~

猜你喜欢

转载自blog.csdn.net/bravetou/article/details/108441905