Android动态数字输入框

基础view如下:
具体的思路实现:
1:展示textview实现
2: 顶层使用透明的edittext.获取焦点/删除文字等。

public class BaseVerificationCodeView extends RelativeLayout {
    private Context mContext;
    private OnCodeFinishListener onCodeFinishListener;

    //TextView的list
    private List<TextView> tvList = new ArrayList<>();

    private GoogleEditText editText;
    /**
     * 输入框数量
     */
    private int mEtNumber;

    /**
     * 输入框类型
     */
    private BaseVerificationCodeView.VCInputType mEtInputType;
    /**
     * 输入框的宽度
     */
    private int mEtWidth;
    /**
     * 输入框的高度
     */
    private int mEtHeight;

    /**
     * 文字颜色
     */
    private int mEtTextColor;

    /**
     * 文字大小
     */
    private float mEtTextSize;

    /**
     * 输入框背景
     */
    private int mEtTextBg;


    //输入框的间距
    private int mEtMargin = 10;

    public void setOnCodeFinishListener(OnCodeFinishListener onCodeFinishListener) {
        this.onCodeFinishListener = onCodeFinishListener;
    }

    public int getmEtNumber() {
        return mEtNumber;
    }

    public void setmEtNumber(int mEtNumber) {
        this.mEtNumber = mEtNumber;
    }

    public BaseVerificationCodeView.VCInputType getmEtInputType() {
        return mEtInputType;
    }

    public void setmEtInputType(BaseVerificationCodeView.VCInputType mEtInputType) {
        this.mEtInputType = mEtInputType;
    }

    public int getmEtWidth() {
        return mEtWidth;
    }

    public void setmEtWidth(int mEtWidth) {
        this.mEtWidth = mEtWidth;
    }

    public int getmEtHeight() {
        return mEtHeight;
    }

    public void setmEtHeight(int mEtHeight) {
        this.mEtHeight = mEtHeight;
    }

    public int getmEtTextColor() {
        return mEtTextColor;
    }

    public void setmEtTextColor(int mEtTextColor) {
        this.mEtTextColor = mEtTextColor;
    }

    public float getmEtTextSize() {
        return mEtTextSize;
    }

    public void setmEtTextSize(float mEtTextSize) {
        this.mEtTextSize = mEtTextSize;
    }

    public int getmEtTextBg() {
        return mEtTextBg;
    }

    public void setmEtTextBg(int mEtTextBg) {
        this.mEtTextBg = mEtTextBg;
    }

    public enum VCInputType {
        NUMBER,
        NUMBERPASSWORD,
        TEXT,
        TEXTPASSWORD,
    }

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

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

    public BaseVerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        @SuppressLint({"Recycle", "CustomViewStyleable"})
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView);
        mEtNumber = typedArray.getInteger(R.styleable.VerificationCodeView_zwidget_vcv_et_number, 4);
        int inputType = typedArray.getInt(R.styleable.VerificationCodeView_zwidget_vcv_et_inputType, VerificationCodeView.VCInputType.NUMBER.ordinal());
        mEtInputType = BaseVerificationCodeView.VCInputType.values()[inputType];
        mEtWidth = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_width, 120);
        mEtHeight = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_height, -1);
        if (mEtHeight == -1) {
            mEtHeight = mEtWidth;
        }
        mEtTextColor = typedArray.getColor(R.styleable.VerificationCodeView_zwidget_vcv_et_text_color, Color.BLACK);
        mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_zwidget_vcv_et_text_size, 16);
        mEtTextBg = typedArray.getResourceId(R.styleable.VerificationCodeView_zwidget_vcv_et_bg, R.drawable.zwidget_vcv_et_code_bg);

        //释放资源
        typedArray.recycle();
        initTextView();
        initEdit();
    }

    /**
     * 设置TextView
     */
    private void initTextView() {
        LinearLayout linearLayout = new LinearLayout(mContext);
        addView(linearLayout);
        LayoutParams llLayoutParams = (LayoutParams) linearLayout.getLayoutParams();
        llLayoutParams.width = LayoutParams.MATCH_PARENT;
        llLayoutParams.height = LayoutParams.WRAP_CONTENT;
        //水平排列
        linearLayout.setOrientation(LinearLayout.HORIZONTAL);
        //内容居中
        linearLayout.setGravity(Gravity.CENTER);
        int childHPadding = 14;
        for (int i = 0; i < mEtNumber; i++) {
            TextView textView = new TextView(mContext);
            linearLayout.addView(textView);

            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(mEtWidth, mEtHeight);
            layoutParams.bottomMargin = childHPadding;
            layoutParams.topMargin = childHPadding;
            layoutParams.leftMargin = childHPadding;
            layoutParams.rightMargin = childHPadding;
            layoutParams.gravity = Gravity.CENTER;
            textView.setLayoutParams(layoutParams);
            textView.setBackgroundResource(mEtTextBg);
            textView.setGravity(Gravity.CENTER);
            textView.setMaxEms(1);
            textView.setMaxLines(1);
            textView.setTextSize(mEtTextSize);
            textView.setTextColor(mEtTextColor);
            switch (mEtInputType) {
                case NUMBERPASSWORD:
                    textView.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
                    break;
                case TEXT:
                    textView.setInputType(InputType.TYPE_CLASS_TEXT);
                    break;
                case TEXTPASSWORD:
                    textView.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
                    break;
                default:
                    textView.setInputType(InputType.TYPE_CLASS_NUMBER);
            }

            tvList.add(textView);
        }
        tvSetFocus(0);
    }

    private void initEdit() {
        editText = new GoogleEditText(mContext);
        addView(editText);
        LayoutParams layoutParams = (LayoutParams) editText.getLayoutParams();
        layoutParams.width = layoutParams.MATCH_PARENT;
        layoutParams.height = mEtHeight;
        editText.setLayoutParams(layoutParams);

        //防止横盘小键盘全屏显示
        editText.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN);
        //隐藏光标
        editText.setCursorVisible(false);
        //最大输入长度
        editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mEtNumber)});
        //输入类型为数字
        switch (mEtInputType) {
            case NUMBERPASSWORD:
                editText.setInputType(InputType.TYPE_NUMBER_VARIATION_PASSWORD);
                break;
            case TEXT:
                editText.setInputType(InputType.TYPE_CLASS_TEXT);
                break;
            case TEXTPASSWORD:
                editText.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
                break;
            default:
                editText.setInputType(InputType.TYPE_CLASS_NUMBER);
        }
        editText.setTextSize(0);
        editText.setBackgroundResource(R.drawable.zwidfet_vcv_et_code_transfer_bg);
        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s != null && !TextUtils.isEmpty(s.toString())) {
                    //如果是最后一位验证码,焦点在最后一个,否者在下一位
                    if (s.length() == mEtNumber) {
                        tvSetFocus(mEtNumber - 1);
                    } else {
                        tvSetFocus(s.length());
                    }

                    //给textView设置数据
                    for (int i = 0; i < s.length(); i++) {
                        tvList.get(i).setText(s.toString().substring(i, i + 1));
                    }
                    for (int i = s.length(); i < mEtNumber; i++) {
                        tvList.get(i).setText("");
                    }
                } else {
                    //一位验证码都没有的情况
                    tvSetFocus(0);
                    for (int i = 0; i < mEtNumber; i++) {
                        tvList.get(i).setText("");
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable s) {
                int length = s.length();
                if (length == mEtNumber) {
                    onCodeFinishListener.onComplete(s.toString());
                }
            }
        });
        showSystemKeyboard(mContext, editText);
    }

    private void tvSetFocus(int index) {
        tvList.get(index).setClickable(true);
        tvList.get(index).setFocusable(true);
        tvList.get(index).setBackgroundResource(mEtTextBg);
    }

    /**
     * 显示系统键盘
     *
     * @param context  Context
     * @param editText EditText
     */
    public static void showSystemKeyboard(Context context, EditText editText) {
        editText.requestFocus();
        InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.showSoftInput(editText, InputMethodManager.SHOW_FORCED);
        }
    }

    /**
     * 隐藏系统键盘
     */
    public void hideSystemKeyboard() {
        InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
        }
    }

    /**
     * 更新输入框颜色背景及字体大小
     */
    public void updateChild() {
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View childAt = getChildAt(i);
            if (childAt instanceof LinearLayout) {
                int childCount1 = ((LinearLayout) childAt).getChildCount();
                for (int i1 = 0; i1 < childCount1; i1++) {
                    View childAt1 = ((LinearLayout) childAt).getChildAt(i1);
                    if (childAt1 instanceof TextView){
                        ((TextView) childAt1).setTextSize(mEtTextSize);
                        ((TextView) childAt1).setTextColor(mEtTextColor);
                        childAt1.setBackgroundResource(mEtTextBg);
                    }
                }
                
            }
        }
        invalidate();
    }

    /**
     * 清空所有输入框内容
     */
    public void clearAllText() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                editText.setText("");
            }
        }, 100);

    }


    public interface OnCodeFinishListener {
        void onComplete(String content);
    }
}

resource如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 自定义验证码输入框-->
    <declare-styleable name="VerificationCodeView">
        <!--输入框的数量-->
        <attr name="zwidget_vcv_et_number" format="integer" />
        <!--输入类型-->
        <attr name="zwidget_vcv_et_inputType">
            <enum name="number" value="0" />
            <enum name="numberPassword" value="1" />
            <enum name="text" value="2" />
            <enum name="textPassword" value="3" />
        </attr>
        <!--输入框的宽度-->
        <attr name="zwidget_vcv_et_width" format="dimension|reference" />
        <!--输入框的高度-->
        <attr name="zwidget_vcv_et_height" format="dimension|reference" />
        <!--输入框文字颜色-->
        <attr name="zwidget_vcv_et_text_color" format="color|reference" />
        <!--输入框文字大小-->
        <attr name="zwidget_vcv_et_text_size" format="dimension|reference" />
        <!--输入框背景-->
        <attr name="zwidget_vcv_et_bg" format="reference" />
    </declare-styleable>
</resources>

遗留问题:
1:无法开启光标,根据光标展示。
2:没有替换背景。

posted @ 2023-02-02 18:34  夏沫琅琊  阅读(61)  评论(0编辑  收藏  举报