自定义验证码输入框:VerificationCodeView

article/2025/8/28 11:27:38

先上两张效果图:

1.java类:

package com...ui;import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;import com...R;import java.lang.reflect.Field;/*** @ClassName: VerificationCodeView* @Desciption: //自定义验证码输入框view* @author: jesse_android* @date: 2018-03-29*/public class VerificationCodeView extends LinearLayout implements TextWatcher, View.OnKeyListener, View.OnFocusChangeListener {private Context mContext;private long endTime = 0;private OnCodeFinishListener onCodeFinishListener;/*** 输入框数量*/private int mEtNumber;/*** 输入框类型*/private VCInputType mEtInputType;/*** 输入框的宽度*/private int mEtWidth;/*** 输入框的高度*/private int mEtHeight;/*** 文字颜色*/private int mEtTextColor;/*** 文字大小*/private float mEtTextSize;/*** 输入框背景*/private int mEtTextBg;private int mCursorDrawable;public OnCodeFinishListener getOnCodeFinishListener() {return onCodeFinishListener;}public void setOnCodeFinishListener(OnCodeFinishListener onCodeFinishListener) {this.onCodeFinishListener = onCodeFinishListener;}public int getmEtNumber() {return mEtNumber;}public void setmEtNumber(int mEtNumber) {this.mEtNumber = mEtNumber;}public VCInputType getmEtInputType() {return mEtInputType;}public void setmEtInputType(VCInputType mEtInputType) {this.mEtInputType = mEtInputType;}public int getmEtWidth() {return mEtWidth;}public void setmEtWidth(int mEtWidth) {this.mEtWidth = mEtWidth;}public int getmEtHeight() {return mEtHeight;}public void setmEtHeight(int mEtHeight) {this.mEtHeight = mEtHeight;}public int getmEtTextColor() {return mEtTextColor;}public void setmEtTextColor(int mEtTextColor) {this.mEtTextColor = mEtTextColor;}public float getmEtTextSize() {return mEtTextSize;}public void setmEtTextSize(float mEtTextSize) {this.mEtTextSize = mEtTextSize;}public int getmEtTextBg() {return mEtTextBg;}public void setmEtTextBg(int mEtTextBg) {this.mEtTextBg = mEtTextBg;}public int getmCursorDrawable() {return mCursorDrawable;}public void setmCursorDrawable(int mCursorDrawable) {this.mCursorDrawable = mCursorDrawable;}public enum VCInputType {NUMBER,NUMBERPASSWORD,TEXT,TEXTPASSWORD,}public VerificationCodeView(Context context, AttributeSet attrs) {super(context, attrs);this.mContext = context;@SuppressLint({"Recycle", "CustomViewStyleable"})TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.vericationCodeView);mEtNumber = typedArray.getInteger(R.styleable.vericationCodeView_vcv_et_number, 4);int inputType = typedArray.getInt(R.styleable.vericationCodeView_vcv_et_inputType, VCInputType.NUMBER.ordinal());mEtInputType = VCInputType.values()[inputType];mEtWidth = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_width, 120);mEtHeight = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_height, 120);mEtTextColor = typedArray.getColor(R.styleable.vericationCodeView_vcv_et_text_color, Color.BLACK);mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_text_size, 16);mEtTextBg = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_bg, R.drawable.bg_et_input_veri_code);mCursorDrawable = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_cursor,R.drawable.bg_et_cursor);//释放资源typedArray.recycle();initView();}@SuppressLint("ResourceAsColor")private void initView() {for (int i = 0; i < mEtNumber; i++) {EditText editText = new EditText(mContext);initEditText(editText, i);addView(editText);if (i == 0) { //设置第一个editText获取焦点,并弹出软键盘editText.setFocusable(true);if(mContext instanceof Activity){((Activity)mContext).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);}}}}private void initEditText(EditText editText, int i) {int childHPadding = 0;int childVPadding = 0;LayoutParams layoutParams = new LayoutParams(mEtWidth,mEtHeight);layoutParams.bottomMargin = childVPadding;layoutParams.topMargin = childVPadding;layoutParams.leftMargin = childHPadding;layoutParams.rightMargin = childHPadding;layoutParams.gravity = Gravity.CENTER;editText.setLayoutParams(layoutParams);editText.setGravity(Gravity.CENTER);editText.setId(i);editText.setCursorVisible(true);editText.setMaxEms(1);editText.setTextColor(mEtTextColor);editText.setTextSize(mEtTextSize);editText.setMaxLines(1);editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});switch (mEtInputType) {case NUMBER:editText.setInputType(InputType.TYPE_CLASS_NUMBER);break;case NUMBERPASSWORD:editText.setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_VARIATION_PASSWORD);break;case TEXT:editText.setInputType(InputType.TYPE_CLASS_TEXT);break;case TEXTPASSWORD:editText.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_PASSWORD);break;default:editText.setInputType(InputType.TYPE_CLASS_NUMBER);}editText.setPadding(0, 0, 0, 0);editText.setOnKeyListener(this);if(mEtTextBg != 0) {editText.setBackgroundResource(mEtTextBg);}//修改光标的颜色(反射)try {if(mCursorDrawable != 0) {Field f = TextView.class.getDeclaredField("mCursorDrawableRes");f.setAccessible(true);f.set(editText, mCursorDrawable);}} catch (Exception ignored) {}editText.addTextChangedListener(this);editText.setOnFocusChangeListener(this);editText.setOnKeyListener(this);}@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {if (s.length() != 0) {focus();}}@Overridepublic boolean onKey(View v, int keyCode, KeyEvent event) {if (keyCode == KeyEvent.KEYCODE_DEL) {backFocus();}return false;}@Overridepublic void setEnabled(boolean enabled) {int childCount = getChildCount();for (int i = 0; i < childCount; i++) {View child = getChildAt(i);child.setEnabled(enabled);}}/*** 获取焦点*/private void focus() {int count = getChildCount();EditText editText;//利用for循环找出还最前面那个还没被输入字符的EditText,并把焦点移交给它。for (int i = 0; i < count; i++) {editText = (EditText) getChildAt(i);if (editText.getText().length() < 1) {editText.setCursorVisible(true);editText.requestFocus();return;} else {editText.setCursorVisible(false);}}//如果最后一个输入框有字符,则返回结果EditText lastEditText = (EditText) getChildAt(mEtNumber - 1);if (lastEditText.getText().length() > 0) {getResult();}}private void backFocus() {//博主手机不好,经常点一次却触发两次`onKey`事件,就设置了一个防止多点击,间隔100毫秒。long startTime = System.currentTimeMillis();EditText editText;//循环检测有字符的`editText`,把其置空,并获取焦点。for (int i = mEtNumber - 1; i >= 0; i--) {editText = (EditText) getChildAt(i);if (editText.getText().length() >= 1 && startTime - endTime > 100) {editText.setText("");editText.setCursorVisible(true);editText.requestFocus();endTime = startTime;return;}}}private void getResult() {StringBuffer stringBuffer = new StringBuffer();EditText editText;for (int i = 0; i < mEtNumber; i++) {editText = (EditText) getChildAt(i);stringBuffer.append(editText.getText());}if (onCodeFinishListener != null) {onCodeFinishListener.onComplete(stringBuffer.toString());}}@Overridepublic void onFocusChange(View v, boolean hasFocus) {if (hasFocus) {focus();}}public interface OnCodeFinishListener {void onComplete(String content);}
}

2.values-attrs.xml中的定义:

<!-- 自定义验证码输入框--><declare-styleable name="vericationCodeView"><!--输入框的数量--><attr name="vcv_et_number" format="integer" /><!--输入类型--><attr name="vcv_et_inputType"><enum name="number" value="0" /><enum name="numberPassword" value="1" /><enum name="text" value="2" /><enum name="textPassword" value="3" /></attr><!--输入框的宽度--><attr name="vcv_et_width" format="dimension|reference" /><!--输入框的高度--><attr name="vcv_et_height" format="dimension|reference" /><!--输入框文字颜色--><attr name="vcv_et_text_color" format="color|reference" /><!--输入框文字大小--><attr name="vcv_et_text_size" format="dimension|reference" /><!--输入框背景--><attr name="vcv_et_bg" format="reference" /><!--光标样式--><attr name="vcv_et_cursor" format="reference" /></declare-styleable>

3.使用:

xml:

<com.shushan.ui.VerificationCodeViewandroid:id="@+id/verification_code_view"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/rl_already_send_to_phone"android:layout_centerHorizontal="true"android:layout_marginTop="29dp"app:vcv_et_width = "60.5dp"app:vcv_et_height = "56.5dp" />

Java:

private VerificationCodeView mVeriCodeView;
mVeriCodeView = (VerificationCodeView) findViewById(R.id.verification_code_view);
mVeriCodeView.setOnCodeFinishListener(this);//验证码输入完毕的回调

可自定义哪些部分看attrs.xml。

使用过程中遇到问题给我留言,会尽快回复。

欢迎参观博主的其他博客。

 

      最后推荐给一些想进大厂或者还没有拿到心仪offer的攻城狮们一本书,由大厂java面试官胡书敏编写,满满的干货,助你进到想去的公司。

 

博主上传资源下载链接:

环状百分比显示视图源码:

https://download.csdn.net/download/yonghuming_jesse/10677919

自制免费无广告小说阅读APP下载:

https://download.csdn.net/download/yonghuming_jesse/10390364

全屏播放视频不拉伸源码:

https://download.csdn.net/download/yonghuming_jesse/10646274

科大讯飞语音评测服务接入源码:

https://download.csdn.net/download/yonghuming_jesse/10616924

android饺子播放器使用源码:

https://download.csdn.net/download/yonghuming_jesse/10619119

视频播放前显示视频第一帧源码:

https://download.csdn.net/download/yonghuming_jesse/10646332


http://chatgpt.dhexx.cn/article/FjUNZMV7.shtml

相关文章

案例:登录中输入验证码(Session及JSP技术应用)

案例&#xff1a;登录中输入验证码(会话技术) 1.案例需求&#xff1a;1.访问带有验证码的登录页面login.jsp2.用户输入用户名&#xff0c;密码以及验证码如果用户和密码输入有误&#xff0c;跳转登录页面。提示&#xff1a;用户或密码错误如果验证码输入有误&#xff0c;跳转登…

《线性代数及其应用 第四版》习题1.4

18. 行化简的结果显示&#xff0c;矩阵B化简后的简化阶梯型只有三行包含主元位置&#xff1a; 根据1.4的定理4&#xff0c;由于B不是每行都有主元位置&#xff0c;因此B的列向量的线性组合不能表示所有R4中的向量。要注意B的列向量也不能张成R3&#xff0c;因为B的列向量位于R4…

同济大学 线性代数 第六版 pdf_线性代数(第六版)【课后习题答案】

来源 线性代数&#xff08;第六版&#xff09; -【课后习题答案】​daanbar.com 网盘下载&#xff1a;https://pan.baidu.com/s/14LN2FrLtxZzKAqtd1ZFoZQ 提取码&#xff1a;375d 同济大学数学系 编 高等教育出版社 第1章 行列式第2章 矩阵及其运算第3章 矩阵的初等变换与线性…

安徽大学线性代数第二章习题册(详细解答)

第二章第一题中4A-3B中间的0换成4&#xff08;感谢通信孔晨皓同学的建议&#xff09; 第五题第二小问2A-EB(EA&#xff09;换成2A-E&#xff08;EA&#xff09;B&#xff0c;不影响后面&#xff0c;因为可以交换&#xff0c;但是错误引导&#xff08;感谢信安赖铭峰同学的建议…

经济数学—线性代数第二版课后习题解析 吴传生 编|高等教育出版社 大学课后习题答案

来源&#xff1a;答案吧 http://www.daanbar.com/book-info/2624.html 经济数学—线性代数第二版课后习题解析 吴传生 编 高等教育出版社 第1章&#xff1a;线性方程组的消元法和矩阵的初等变换 第2章&#xff1a;行列式克拉默法则 第3章&#xff1a;矩阵的运算 第4章&am…

安徽大学(线性代数第一章详细答案)

附录1 #pragma warning(disable:4996) #include <cstdio> #include <cmath>#define MAXN 100 #define zero(x) (fabs(x)<1e-10)struct mat{int n, m;double data[MAXN][MAXN]; }; double det(const mat &a){int i, j, k, sign 0;double b[MAXN][MAXN], re…

工程数学线性代数 同济大学版 第六版 课后习题答案 高等数学 大学数学 线性代数 课后题答案与解析 考试复习提纲

大学 高等数学 大学线性代数 第六版 同济大学版 工程数学线性代数 课后习题答案 大学高等数学 大学线性代数 第六版 同济大学版 课后习题答案工程数学线性代数 同济大学数学系编 高等教育出版社出版 注意:答案在文章最下方 前言 第1章 行列式 课后习题答案 1 二阶与三阶行列…

经济应用数学基础二 线性代数 (第四版) 赵树嫄 编 中国人大版 课后习题答案

更多答案:http://www.daanbar.com/book-info/122.html 经济应用数学基础二 线性代数 &#xff08;第四版&#xff09; 赵树嫄 编 中国人大版 第1章 行列式第2章 矩阵第3章 线性方程组第4章 矩阵的特征值第5章 二次型 第1章 行列式