preface

Recently write outsourcing met a demand to write a similar to didi what kind of verification code input box, to the online check, there are ready-made, but based on their own custom view weak this piece, decided to achieve their own

How to implement

Most of the things you do on the web are you put an array of TextViews on an Edittext, and the TextViews do that, and that’s exactly what I want to do, so here’s an example

The general design idea is reflected in this figure, let’s start to implement

layout

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:id="@+id/contanier"
        android:layout_centerInParent="true"
        android:gravity="center_vertical"
        android:orientation="horizontal"
        android:showDividers="middle"></LinearLayout>

    <EditText
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/edit"
        android:inputType="number"/>
</RelativeLayout>
Copy the code

This is a custom viewGroup

The core code

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mheightMeasure=heightMeasureSpec;
        int heightMode=MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode==MeasureSpec.AT_MOST){
            mheightMeasure=MeasureSpec.makeMeasureSpec((int)dp2px(50,getContext()),MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, mheightMeasure);
    }
Copy the code

First of all, since it is a custom viewgroup, wrapContent is invalid (wrapContent is equivalent to matchparent in custom view), so we need to customize warpContent. Then we start to initialize our parts

    private LinearLayout mContainerLi;
    private EditText mInputEt;
    private TextView[] textViews;
    private int mEtnumber;
    private int mTvCountnumber;
    private int mEtWidth;
    private int mAlpha;
    private Drawable mEtDividerDrawable;
    private int mEtTextColor;
    private float mEtTextSize;
    private Drawable mBackGroundDrawable;

    private ActivationCodeTextWatcher mTextWatcher=new ActivationCodeTextWatcher();
Copy the code

This includes the TextView which is the width and transparency of that square, the font size, the color and so on and the background image of the controls, as well as an observation tool class for our custom implementation of the TextView

private class ActivationCodeTextWatcher 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(); if (inputStr ! = null && ! inputStr.equals("")) { setText(inputStr); mInputEt.setText(""); }}}Copy the code

Then start to initialize the controller

 private void initUI() {
        initTextViews(getContext(),mEtnumber,mEtWidth,mEtDividerDrawable,mEtTextSize,mEtTextColor);
        initcontainer(textViews);
        setListener();

    }
Copy the code

Initialization of small squares

private void initTextViews(Context context, int mEtnumber, int mEtWidth, Drawable mEtDividerDrawable, float mEtTextSize, int mEtTextColor) { mInputEt.setCursorVisible(false); mInputEt.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mEtnumber)}); if (mEtDividerDrawable! = null) {mEtDividerDrawable. SetBounds (0, 0, mEtDividerDrawable getMinimumWidth (), mEtDividerDrawable. GetMinimumHeight ()); mContainerLi.setDividerDrawable(mEtDividerDrawable); } textViews=new TextView[mEtnumber]; for (int i=0; i<textViews.length; i++){ TextView textView=new TextView(context); textView.setTextSize(mEtTextSize); textView.setTextColor(mEtTextColor); textView.setWidth(mEtWidth); textView.setHeight(mEtWidth); textView.setBackground(mBackGroundDrawable); textView.setAlpha(mAlpha); textView.setGravity(Gravity.CENTER); textView.setFocusable(false); textViews[i]=textView; }}Copy the code

In the LinearLayout, first hide the cursor and set the maximum value that can be input to prevent bugs. Then set the Divider of the LinearLayout and set the properties of the TextViews in the TextView collection

Put these little squares into a LinearLayout

private void initcontainer(TextView[] textViews) { for (int i=0; i<textViews.length; i++){ mContainerLi.addView(textViews[i]); }}Copy the code

Custom implementation input, delete

private void setListener() { mInputEt.addTextChangedListener(mTextWatcher); mInputEt.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View v, int keyCode, KeyEvent event) { if (keyCode==KeyEvent.KEYCODE_DEL&&event.getAction()==KeyEvent.ACTION_DOWN){ onKeyDelete(); return true; } return false; }}); } private void onKeyDelete() { for (int i = textViews.length - 1; i >= 0; i--) { TextView tv = textViews[i]; if (! tv.getText().toString().trim().equals("")) { tv.setText(tv.getText().subSequence(0,tv.getText().length()-1)); If (inputCompleteListener! = null) { inputCompleteListener.deleteContent(); } tv.setBackgroundDrawable(mBackGroundDrawable); if (i < mEtnumber - 1) { textViews[i + 1].setBackgroundDrawable(mBackGroundDrawable); } break; } } } public void setText(String inputContent){ for (int i=0; i<textViews.length; i++){ TextView tv=textViews[i]; if (tv.getText().toString().trim().equals("")||tv.getText().toString().length()<mTvCountnumber){ tv.setText(tv.getText().toString()+inputContent); if (inputCompleteListener! =null){ inputCompleteListener.inputComplete(); } if (tv.getText().toString().length()==mTvCountnumber){ tv.setBackgroundDrawable(mBackGroundDrawable); if (i<mEtnumber-1){ textViews[i+1].setBackgroundDrawable(mBackGroundDrawable); } } break; }}}Copy the code

These two functions are key, one for delete and one for add.

Implementation effect

Finally, let’s look at the implementation

completed