先上效果图
![](https://i-blog.csdnimg.cn/blog_migrate/a17adb69ea9332ca6e8f1e8d4cb9d5d2.png)
attrs
<!--验证码输入框-->
<declare-styleable name="VerificationCodeView">
<attr name="codeLength" format="integer" />
<attr name="beforeLineColor" format="color" />
<attr name="currentLineColor" format="color" />
<attr name="bgHeightWidth" format="dimension" />
<attr name="bgBorderRadius" format="dimension" />
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
<attr name="space" format="dimension" />
<attr name="lineWidth" format="dimension" />
<attr name="paddingStart" format="dimension" />
<attr name="paddingEnd" format="dimension" />
<attr name="paddingTop" format="dimension" />
<attr name="paddingBottom" format="dimension" />
</declare-styleable>
java文件
/**
* 自定义输入验证码控件
*
* @author: whr
* @date: 2021/01/21
*/
public class VerificationCodeView extends androidx.appcompat.widget.AppCompatEditText {
/**
* 间隔
*/
private float space = 45;
/**
* 验证码长度
*/
private int codeLength = 6;
/**
* 未输入下划线颜色
*/
private int beforeLineColor = Color.WHITE;
/**
* 当前输入下划线颜色
*/
private int currentLineColor = Color.WHITE;
/**
* 文字颜色
*/
private int textColor = Color.WHITE;
/**
* 文本字体大小
*/
private float textSize = 70f;
/**
* 验证码框下划线宽度
*/
private int lineHeight = 4;
/**
* 已输入背景框圆角
*/
private float bgBorderRadius = 24;
/**
* 已输入背景框高度
*/
private float bgBorderHeight = 50;
/**
* 文本画笔
*/
private Paint mTextPaint;
/**
* 背景框画笔
*/
private Paint mBorderPaint;
/**
* 输入的密码长度
*/
private int mInputLength;
/**
* 输入结束监听
*/
private OnInputFinishListener mOnInputFinishListener;
/**
* 左右间距
*/
private float paddingStart, paddingEnd, paddingTop, paddingBottom = 0;
private String text;
/**
* 构造方法
*
* @param context
* @param attrs
*/
public VerificationCodeView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerificationCodeView);
codeLength = array.getInteger(R.styleable.VerificationCodeView_codeLength, codeLength);
beforeLineColor = array.getInteger(R.styleable.VerificationCodeView_beforeLineColor, beforeLineColor);
currentLineColor = array.getInteger(R.styleable.VerificationCodeView_currentLineColor, currentLineColor);
bgBorderHeight = array.getDimension(R.styleable.VerificationCodeView_bgHeightWidth, bgBorderHeight);
bgBorderRadius = array.getDimension(R.styleable.VerificationCodeView_bgBorderRadius, bgBorderRadius);
space = array.getDimension(R.styleable.VerificationCodeView_space, space);
lineHeight = (int) array.getDimension(R.styleable.VerificationCodeView_lineHeight, lineHeight);
textSize = array.getDimension(R.styleable.VerificationCodeView_textSize, textSize);
textColor = array.getInteger(R.styleable.VerificationCodeView_textColor, textColor);
paddingStart = array.getDimension(R.styleable.VerificationCodeView_paddingStart, paddingStart);
paddingEnd = array.getDimension(R.styleable.VerificationCodeView_paddingEnd, paddingEnd);
paddingTop = array.getDimension(R.styleable.VerificationCodeView_paddingTop, paddingTop);
paddingBottom = array.getDimension(R.styleable.VerificationCodeView_paddingBottom, paddingBottom);
// 初始化文字画笔
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(textColor);
mTextPaint.setTextSize(textSize);
// 初始化下划线
mBorderPaint = new Paint();
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setColor(beforeLineColor);
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStrokeWidth(lineHeight);
mBorderPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取控件宽高的显示模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取宽高的尺寸值 固定值的宽度
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//设置宽高默认为建议的最小宽高
int width;
int height;
// MeasureSpec父布局传递给后代的布局要求 包含 确定大小和三种模式
// EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
// AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
// UNSPECIFIED:表示子布局想要多大就多大,很少使用
if (widthMode == MeasureSpec.EXACTLY) {
width = widthSize;
} else {
width = widthSize;
}
if (heightMode == MeasureSpec.EXACTLY) {
height = heightSize;
} else {
height = (int) (bgBorderHeight + paddingTop + paddingBottom + lineHeight * 2);
}
//设置测量的宽高
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 这三行代码非常关键,大家可以注释点在看看效果
Paint paint = new Paint();
paint.setColor(Color.WHITE);
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
// 计算每个密码框宽度
int rectWidth = (int) ((getWidth() - space * (codeLength - 1) - paddingStart - paddingEnd) / codeLength);
int bottom = (int) (paddingStart + bgBorderHeight);
// 绘制背景
for (int i = 0; i < codeLength; i++) {
int left = (int) (paddingStart + lineHeight + (rectWidth + space) * i);
int right = (int) (left + rectWidth - paddingEnd - lineHeight);
int top = (int) paddingTop + lineHeight;
if (i < mInputLength) {
//绘制背景色
mBorderPaint.setColor(currentLineColor);
mBorderPaint.setStyle(Paint.Style.FILL_AND_STROKE);
RectF rectF = new RectF(left, top, right, bottom);
canvas.drawRoundRect(rectF, bgBorderRadius, bgBorderRadius, mBorderPaint);
//绘制文本
int cx = left + rectWidth / 2;
int cy = (bottom / 2 + WindowUtils.px2dp(textSize));
String[] c = text.split("");
mTextPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(c[i], cx, cy, mTextPaint);
} else {
if (i == mInputLength) {
mBorderPaint.setColor(currentLineColor);
} else {
mBorderPaint.setColor(beforeLineColor);
}
canvas.drawLine(left, bottom, right, bottom, mBorderPaint);
}
}
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
super.onTextChanged(text, start, lengthBefore, lengthAfter);
this.mInputLength = text.toString().length();
if (mInputLength <= codeLength) {
this.text = text.toString();
invalidate();
if (mInputLength == codeLength && mOnInputFinishListener != null) {
mOnInputFinishListener.onInputFinish(text.toString());
}
}
}
public interface OnInputFinishListener {
/**
* 密码输入结束监听
*
* @param password
*/
void onInputFinish(String password);
}
/**
* 设置输入完成监听
*
* @param onInputFinishListener
*/
public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
this.mOnInputFinishListener = onInputFinishListener;
}
}
使用
<com.whr.demo.mydemolist.ui.view.VerificationCodeView
android:id="@+id/ed_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/transparent"
android:cursorVisible="false"
android:enabled="true"
android:focusable="true"
android:inputType="number"
android:maxLength="6"
app:beforeLineColor="#f5f5f5"
app:bgBorderRadius="30dp"
app:bgHeightWidth="48dp"
app:codeLength="6"
app:currentLineColor="#fd4f00"
app:lineHeight="2dp"
app:space="15dp"
app:textColor="#ffffff"
app:textSize="66dp" />
属性说明:
-
codeLength:验证码长度
-
beforeLineColor:未输入框下划线颜色
-
currentLineColor:当前输入下划线颜色
-
bgHeightWidth:已输入框背景色
-
bgBorderRadius:已输入框圆角大小
-
textColor:文本颜色
-
textSize:文本大小
-
space:文本框间距
-
lineHeight:下划线高度
-
paddingStart:已输入文本距边框start间距
-
paddingEnd:已输入文本距边框end间距
-
paddingTop:已输入文本距边框top间距
-
paddingBottom:已输入文本距边框bottom间距