Customize your own underlined EditText input box

Let's see the effect first

 

In the middle of the picture is the style of the input box. The number of input boxes, the spacing between each input box, the color of the input text and the bottom line can be changed dynamically. Next is the time to roll up the code

1. Now create attrs.xml in the values folder and copy the style

 <declare-styleable name="VerifyEditText">
        <! -- number of verification codes -- >
        <attr name="totalCount" format="integer" />
        <! -- interval of each verification code -- >
        <attr name="intervalLength" format="integer" />
        <! -- color of bottom line -- >
        <attr name="lineColor" format="color" />
        <! -- input box text color -- >
        <attr name="textColor" format="color" />
    </declare-styleable>

2. Next write a class to inherit EditText

/**
 * Created by ytt on 2018/7/27.
 * Custom verification code input box
 */
public class VerifyEditText extends android.support.v7.widget.AppCompatEditText {
    /**
     * Width and height of this control
     */
    private int width;
    private int height;
    private OnVerifyInputCompleteListener listener;
    //TODO saves the set of verification codes entered
    private StringBuffer sb = new StringBuffer();
    //Line brush at bottom
    private Paint mLinePaint;
    //A brush for writing
    private Paint mTextPaint;
    //Calculated width of each input box
    private int textLineLength;

    //Number of verification codes
    private int totalCount;
    //Distance between each verification code
    private int intervalLength;
    //Color of bottom line
    private int lineColor;
    //Enter the color of the text
    private int textColor;

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

    public VerifyEditText(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.editTextStyle);
    }

    public VerifyEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.VerifyEditText, defStyleAttr, 0);
        totalCount = typedArray.getInt(R.styleable.VerifyEditText_totalCount, 4);
        intervalLength = typedArray.getInt(R.styleable.VerifyEditText_intervalLength, 30);
        lineColor = typedArray.getColor(R.styleable.VerifyEditText_lineColor, getColor(R.color.textE6));
        textColor = typedArray.getColor(R.styleable.VerifyEditText_textColor, getColor(R.color.text3));
        typedArray.recycle();
        initView();
    }

    private void initView() {
        setBackground(null);
        setMaxLines(1);
        setLines(1);
        /**
         * You must override setOnTouchListener to handle touch events by itself, otherwise the cursor can move
         * You must override setOnLongClickListener or long press can copy the verification code
         * Or the cursor can move~~
         */
        setOnLongClickListener(new OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                return true;
            }
        });
        setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.showSoftInput(VerifyEditText.this, 0);
                return true;
            }
        });
        //TODO set the font input to be transparent and invisible
        setTextColor(getColor(android.R.color.transparent));

        mLinePaint = new Paint();
        mLinePaint.setColor(lineColor);
        mLinePaint.setAntiAlias(true);
        mLinePaint.setStrokeWidth(3);

        mTextPaint = new Paint();
        mTextPaint.setTextSize(sp2px(22));
        mTextPaint.setFakeBoldText(true);
        mTextPaint.setColor(textColor);
        mTextPaint.setAntiAlias(true);
        //TODO adds listening of input characters
        addTextChangedListener(textWatcher);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
        //Width of each input text
        textLineLength = (width - (totalCount - 1) * intervalLength) / totalCount;
        //Locate the initial display position of the cursor
        setPadding(textLineLength / 2, getPaddingTop(), getPaddingRight(), getPaddingBottom());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (totalCount <= 0) {
            return;
        }
        int currentLength = 0;
        //TODO draw text
        for (int i = 0; i < totalCount; i++) {
            String textString = String.valueOf((sb != null && sb.length() > i) ? sb.charAt(i) : "");
            canvas.drawText(textString, currentLength + textLineLength / 2 - mTextPaint.measureText(textString) / 2, height / 2 + mTextPaint.getTextSize() / 2, mTextPaint);
            currentLength += textLineLength + intervalLength;
        }
        //TODO draws the line at the bottom of the text
        currentLength = 0;
        for (int i = 0; i < totalCount; i++) {
            canvas.drawLine(currentLength, height - 3, textLineLength * (i + 1) + intervalLength * i, height - 3, mLinePaint);
            currentLength += textLineLength + intervalLength;
        }
    }

    private TextWatcher textWatcher = 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) {
        }

        @Override
        public void afterTextChanged(Editable s) {
            sb.delete(0, sb.length());
            if (!TextUtils.isEmpty(s.toString())) {
                //TODO can only input more words of the specified totalCount to be deleted
                if (s.toString().length() > totalCount) {
                    s.delete(totalCount, s.length());
                    return;
                }
                sb.append(s);
                if (s.toString().length() == totalCount && listener != null) {
                    listener.onCompleteInput(sb.toString());
                }

            }
            int paddingLeft;
            /**
             * Calculate the position of the cursor after the verification code input
             * If the verification code has been entered, the cursor needs to be displayed after the last character instead of the next text input box
             * */
            if (sb.length() < totalCount) {
                paddingLeft = (int) ((textLineLength + intervalLength) * sb.length()
                        + textLineLength / 2 - getPaint().measureText(!TextUtils.isEmpty(sb.toString()) ? sb.toString() : ""));

            } else {
                paddingLeft = (int) ((textLineLength + intervalLength) * (sb.length() - 1)
                        + (mTextPaint.measureText(sb.substring(sb.length() - 2, sb.length() - 1)) / 2)
                        + textLineLength / 2 - getPaint().measureText(!TextUtils.isEmpty(sb.toString()) ? sb.toString() : ""));
            }
            setPadding(paddingLeft, getPaddingTop(), getPaddingRight(), getPaddingBottom());
        }
    };

    /**
     * Set input complete listening
     */
    public void setOnVerifyInputCompleteListener(OnVerifyInputCompleteListener listener) {
        this.listener = listener;
    }

    /**
     * Get the input verification code
     */
    public String getVerifyCode() {
        return sb.toString();
    }

    public int getColor(int id) {
        return ContextCompat.getColor(getContext(), id);
    }

    public int sp2px(float spValue) {
        final float fontScale = getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }
}

3. Use VerifyEditText

 <cn.test.view.VerifyEditText
        android:id="@+id/verifyEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="50dp"
        android:layout_marginRight="50dp"
        android:inputType="text" />

Styles displayed in xml

Summary of problems encountered:

1. After input, the cursor can be displayed in the corresponding position because the number of calculation inputs is used to set padding for the cursor, but the input text is only set to transparent color, which actually exists, so that the cursor can click and long press to copy all.. Therefore, the ontouch and onlongclick events must be overridden. The ontouch event only allows the keyboard to be turned on, and other operations are not allowed. For details of the automatic code operations, you can view the ontouch events in TextView

2. After entering the text, you can wrap the line. lines need to be set for this bar

Nothing else for the time being. Code can be copied directly. Oh

Keywords: Android xml

Added by Credo on Sat, 01 Feb 2020 06:18:03 +0200