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