请教一种效果的实现方法

图片说明

就是这种效果,有几个要求:

1、使用的不是定制的键盘,而是系统自带的键盘。

2、显示是四个分开的数字,但可以连续输入,按删除按钮会逐个删除,用户**无法**通过点击选取其中某个进行单独修改。

不知道有没有现成的控件,或者用什么方法可以实现。我现在脑袋有点僵了,想不出来。求大神赐教。

效果图:
图片说明

直接把类复制进去 把属性放到values下的attrs.xml文件中 即可使用,下划线的颜色可自行定义
示例:

<VerifyCodeNumView
        android:id="@+id/icv"
        android:layout_width="match_parent"
        android:layout_height="54dp"
        android:layout_marginTop="32dp"
        android:focusable="true"
        app:icv_et_bg_focus="@drawable/shape_code_et_bg_focus"
        app:icv_et_bg_normal="@drawable/shape_code_et_bg_normal"
        app:icv_et_number="4"
        app:icv_et_text_color="#404040"
        app:icv_et_text_size="27dp"
        app:icv_et_width="54dp"/>

类:

public class VerifyCodeNumView extends RelativeLayout {

    private static final String TAG = VerifyCodeNumView.class.getSimpleName();

    private LinearLayout containerEt;

    private EditText et;
    // 输入框数量
    private int mEtNumber;
    // 输入框的宽度
    private int mEtWidth;
    //输入框分割线
    private Drawable mEtDividerDrawable;
    //输入框文字颜色
    private int mEtTextColor;
    //输入框文字大小
    private float mEtTextSize;
    //输入框获取焦点时背景
    private Drawable mEtBackgroundDrawableFocus;
    // 输入框没有焦点时背景
    private Drawable mEtBackgroundDrawableNormal;

    //存储TextView的数据 数量由自定义控件的属性传入
    private EditText[] mTextViews;

    private MyTextWatcher myTextWatcher = new MyTextWatcher();

    private InputMethodManager imm;

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

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

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

    //初始化 布局和属性
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        LayoutInflater.from(context).inflate(R.layout.layout_identify_num_code, this);
        containerEt = (LinearLayout) this.findViewById(R.id.container_et);
        et = (EditText) this.findViewById(R.id.et);

        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView, defStyleAttr, 0);
        mEtNumber = typedArray.getInteger(R.styleable.VerificationCodeView_icv_et_number, 1);
        mEtWidth = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_icv_et_width, 42);
        mEtDividerDrawable = typedArray.getDrawable(R.styleable.VerificationCodeView_icv_et_divider_drawable);
        mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.VerificationCodeView_icv_et_text_size, 16);
        mEtTextColor = typedArray.getColor(R.styleable.VerificationCodeView_icv_et_text_color, Color.BLACK);
        mEtBackgroundDrawableFocus = typedArray.getDrawable(R.styleable.VerificationCodeView_icv_et_bg_focus);
        mEtBackgroundDrawableNormal = typedArray.getDrawable(R.styleable.VerificationCodeView_icv_et_bg_normal);
        //释放资源
        typedArray.recycle();


        Log.d(TAG, "mEtTextSize:"+mEtTextSize);
        // 当xml中未配置时 这里进行初始配置默认图片
//        if (mEtDividerDrawable == null) {
//            mEtDividerDrawable = context.getResources().getDrawable(R.drawable.shape_divider_identifying);
//        }

        if (mEtBackgroundDrawableFocus == null) {
            mEtBackgroundDrawableFocus = context.getResources().getDrawable(R.drawable.shape_icv_et_bg_focus);
        }

        if (mEtBackgroundDrawableNormal == null) {
            mEtBackgroundDrawableNormal = context.getResources().getDrawable(R.drawable.shape_icv_et_bg_normal);
        }

        imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);

        initUI();
    }

    // 初始UI
    private void initUI() {
        initTextViews(getContext(), mEtNumber, mEtWidth, mEtDividerDrawable, mEtTextSize, mEtTextColor);
        initEtContainer(mTextViews);
        setListener();
    }


    public void focule() {
        et.requestFocus();
        imm.showSoftInput(et, InputMethodManager.RESULT_UNCHANGED_SHOWN);
        et.setSelection(et.getText().length());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 设置当 高为 warpContent 模式时的默认值 为 50dp
        int mHeightMeasureSpec = heightMeasureSpec;

        int heightMode = MeasureSpec.getMode(mHeightMeasureSpec);
        if (heightMode == MeasureSpec.AT_MOST) {
            mHeightMeasureSpec = MeasureSpec.makeMeasureSpec((int) dp2px(50, getContext()), MeasureSpec.EXACTLY);
        }

        super.onMeasure(widthMeasureSpec, mHeightMeasureSpec);
    }


    //初始化TextView
    private void initTextViews(Context context, int etNumber, int etWidth, Drawable etDividerDrawable, float etTextSize, int etTextColor) {
        // 设置 editText 的输入长度
        et.setCursorVisible(true);//将光标隐藏
        et.setFilters(new InputFilter[]{new InputFilter.LengthFilter(etNumber)}); //最大输入长度
        // 设置分割线的宽度
        if (etDividerDrawable != null) {
            etDividerDrawable.setBounds(0, 0, etDividerDrawable.getMinimumWidth(), etDividerDrawable.getMinimumHeight());
            containerEt.setDividerDrawable(etDividerDrawable);
        }
        mTextViews = new EditText[etNumber];
        for (int i = 0; i < mTextViews.length; i++) {
            EditText textView = new EditText(context);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, etTextSize);
            textView.setTextColor(etTextColor);
            textView.setWidth(etWidth);
            textView.setHeight(etWidth);
            textView.setCursorVisible(true);
            textView.setBackgroundDrawable(mEtBackgroundDrawableNormal);
            textView.setGravity(Gravity.CENTER);

            textView.setFocusable(false);
            textView.setTypeface(Typeface.DEFAULT_BOLD);

            mTextViews[i] = textView;
        }
    }

    //初始化存储TextView 的容器
    private void initEtContainer(EditText[] mTextViews) {
        for (int i = 0; i < mTextViews.length; i++) {
            containerEt.addView(mTextViews[i]);
            if (i < mTextViews.length - 1) {
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0, 1);
                layoutParams.weight = 1;
                containerEt.addView(new View(getContext()), layoutParams);
            }
        }
    }


    private void setListener() {
        et.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if(event.getAction()==MotionEvent.ACTION_UP) {
                    imm.showSoftInput(et, InputMethodManager.RESULT_UNCHANGED_SHOWN);
                    et.setSelection(et.getText().length());
                }
                return true;
            }
        });
        // 监听输入内容
        et.addTextChangedListener(myTextWatcher);

    }

    // 给TextView 设置文字
    private void setText(String inputContent) {
        Log.d(TAG, "setText:"+et.getText().toString());
        char[] chars = inputContent.toCharArray();
        for (int i = 0; i < mTextViews.length; i++) {
            EditText tv = mTextViews[i];
            if (i < chars.length) {
                tv.setText(String.valueOf(chars[i]));
            }else {
                tv.setText("");
            }
            if (i < chars.length) {
                tv.setBackground(mEtBackgroundDrawableFocus);
            }else {
                tv.setBackground(mEtBackgroundDrawableNormal);
            }
        }
        if (inputCompleteListener != null) {
            inputCompleteListener.inputComplete();
        }
    }

    StringBuffer buffer = new StringBuffer();
    /**
     * 获取输入文本
     *
     * @return string
     */
    public String getInputContent() {
        buffer.delete(0, buffer.length());
        for (EditText tv : mTextViews) {
            buffer.append(tv.getText().toString().trim());
        }
        return buffer.toString();
    }

    /**
     * 删除输入内容
     */
    public void clearInputContent() {
        for (int i = 0; i < 4; i++) {
            mTextViews[i].setBackground(mEtBackgroundDrawableNormal);
            mTextViews[i].setText("");
        }
        et.setText("");
    }

    /**
     * 设置输入框个数
     * @param etNumber
     */
    public void setEtNumber(int etNumber) {
        this.mEtNumber = etNumber;
        et.removeTextChangedListener(myTextWatcher);
        containerEt.removeAllViews();
        initUI();
    }


    /**
     * 获取输入的位数
     *
     * @return int
     */
    public int getEtNumber() {
        return mEtNumber;
    }

    // 输入完成 和 删除成功 的监听
    private InputCompleteListener inputCompleteListener;

    public void setInputCompleteListener(InputCompleteListener inputCompleteListener) {
        this.inputCompleteListener = inputCompleteListener;
    }

    public interface InputCompleteListener {
        void inputComplete();
    }


    public float dp2px(float dpValue, Context context) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                dpValue, context.getResources().getDisplayMetrics());
    }

    public float sp2px(float spValue, Context context) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                spValue, context.getResources().getDisplayMetrics());
    }

    private class MyTextWatcher implements 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) {

        }

        @Override
        public void afterTextChanged(Editable editable) {
            String inputStr = editable.toString();
            setText(inputStr);
        }
    }

}

属性attr:

    <declare-styleable name="VerificationCodeView">
        <!--输入框的数量-->
        <attr name="icv_et_number" format="integer" />
        <!--输入框的宽度-->
        <attr name="icv_et_width" format="dimension|reference" />
        <!--输入框之间的分割线-->
        <attr name="icv_et_divider_drawable" format="reference" />
        <!--输入框文字颜色-->
        <attr name="icv_et_text_color" format="color|reference" />
        <!--输入框文字大小-->
        <attr name="icv_et_text_size" format="dimension|reference" />
        <!--输入框获取焦点时边框-->
        <attr name="icv_et_bg_focus" format="reference" />
        <!--输入框没有焦点时边框-->
        <attr name="icv_et_bg_normal" format="reference" />
    </declare-styleable>

https://blog.csdn.net/gf771115/article/details/86245745
https://www.jianshu.com/p/0495fc3f09ba