自定义验证码输入框:VerificationCodeView

先上两张效果图:


1.java类:

[java]  view plain  copy
  1. package com...ui;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.app.Activity;  
  5. import android.content.Context;  
  6. import android.content.res.TypedArray;  
  7. import android.graphics.Color;  
  8. import android.text.Editable;  
  9. import android.text.InputFilter;  
  10. import android.text.InputType;  
  11. import android.text.TextWatcher;  
  12. import android.util.AttributeSet;  
  13. import android.view.Gravity;  
  14. import android.view.KeyEvent;  
  15. import android.view.View;  
  16. import android.view.WindowManager;  
  17. import android.widget.EditText;  
  18. import android.widget.LinearLayout;  
  19. import android.widget.TextView;  
  20.   
  21.   
  22. import com...R;  
  23.   
  24. import java.lang.reflect.Field;  
  25.   
  26. /** 
  27.  * @ClassName: VerificationCodeView 
  28.  * @Desciption: //自定义验证码输入框view 
  29.  * @author: jesse_android 
  30.  * @date: 2018-03-29 
  31.  */  
  32.   
  33. public class VerificationCodeView extends LinearLayout implements TextWatcher, View.OnKeyListener, View.OnFocusChangeListener {  
  34.   
  35.     private Context mContext;  
  36.     private long endTime = 0;  
  37.     private OnCodeFinishListener onCodeFinishListener;  
  38.   
  39.     /** 
  40.      * 输入框数量 
  41.      */  
  42.     private int mEtNumber;  
  43.   
  44.     /** 
  45.      * 输入框类型 
  46.      */  
  47.     private VCInputType mEtInputType;  
  48.     /** 
  49.      * 输入框的宽度 
  50.      */  
  51.     private int mEtWidth;  
  52.   
  53.     /** 
  54.      * 输入框的高度 
  55.      */  
  56.     private int mEtHeight;  
  57.   
  58.     /** 
  59.      * 文字颜色 
  60.      */  
  61.     private int mEtTextColor;  
  62.   
  63.     /** 
  64.      * 文字大小 
  65.      */  
  66.     private float mEtTextSize;  
  67.   
  68.     /** 
  69.      * 输入框背景 
  70.      */  
  71.     private int mEtTextBg;  
  72.   
  73.     private int mCursorDrawable;  
  74.   
  75.     public OnCodeFinishListener getOnCodeFinishListener() {  
  76.         return onCodeFinishListener;  
  77.     }  
  78.   
  79.     public void setOnCodeFinishListener(OnCodeFinishListener onCodeFinishListener) {  
  80.         this.onCodeFinishListener = onCodeFinishListener;  
  81.     }  
  82.   
  83.     public int getmEtNumber() {  
  84.         return mEtNumber;  
  85.     }  
  86.   
  87.     public void setmEtNumber(int mEtNumber) {  
  88.         this.mEtNumber = mEtNumber;  
  89.     }  
  90.   
  91.     public VCInputType getmEtInputType() {  
  92.         return mEtInputType;  
  93.     }  
  94.   
  95.     public void setmEtInputType(VCInputType mEtInputType) {  
  96.         this.mEtInputType = mEtInputType;  
  97.     }  
  98.   
  99.     public int getmEtWidth() {  
  100.         return mEtWidth;  
  101.     }  
  102.   
  103.     public void setmEtWidth(int mEtWidth) {  
  104.         this.mEtWidth = mEtWidth;  
  105.     }  
  106.   
  107.     public int getmEtHeight() {  
  108.         return mEtHeight;  
  109.     }  
  110.   
  111.     public void setmEtHeight(int mEtHeight) {  
  112.         this.mEtHeight = mEtHeight;  
  113.     }  
  114.   
  115.     public int getmEtTextColor() {  
  116.         return mEtTextColor;  
  117.     }  
  118.   
  119.     public void setmEtTextColor(int mEtTextColor) {  
  120.         this.mEtTextColor = mEtTextColor;  
  121.     }  
  122.   
  123.     public float getmEtTextSize() {  
  124.         return mEtTextSize;  
  125.     }  
  126.   
  127.     public void setmEtTextSize(float mEtTextSize) {  
  128.         this.mEtTextSize = mEtTextSize;  
  129.     }  
  130.   
  131.     public int getmEtTextBg() {  
  132.         return mEtTextBg;  
  133.     }  
  134.   
  135.     public void setmEtTextBg(int mEtTextBg) {  
  136.         this.mEtTextBg = mEtTextBg;  
  137.     }  
  138.   
  139.     public int getmCursorDrawable() {  
  140.         return mCursorDrawable;  
  141.     }  
  142.   
  143.     public void setmCursorDrawable(int mCursorDrawable) {  
  144.         this.mCursorDrawable = mCursorDrawable;  
  145.     }  
  146.   
  147.     public enum VCInputType {  
  148.         NUMBER,  
  149.         NUMBERPASSWORD,  
  150.         TEXT,  
  151.         TEXTPASSWORD,  
  152.     }  
  153.   
  154.     public VerificationCodeView(Context context, AttributeSet attrs) {  
  155.         super(context, attrs);  
  156.         this.mContext = context;  
  157.         @SuppressLint({"Recycle""CustomViewStyleable"})  
  158.         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.vericationCodeView);  
  159.         mEtNumber = typedArray.getInteger(R.styleable.vericationCodeView_vcv_et_number, 4);  
  160.         int inputType = typedArray.getInt(R.styleable.vericationCodeView_vcv_et_inputType, VCInputType.NUMBER.ordinal());  
  161.         mEtInputType = VCInputType.values()[inputType];  
  162.         mEtWidth = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_width, 120);  
  163.         mEtHeight = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_height, 120);  
  164.         mEtTextColor = typedArray.getColor(R.styleable.vericationCodeView_vcv_et_text_color, Color.BLACK);  
  165.         mEtTextSize = typedArray.getDimensionPixelSize(R.styleable.vericationCodeView_vcv_et_text_size, 16);  
  166.         mEtTextBg = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_bg, R.drawable.bg_et_input_veri_code);  
  167.         mCursorDrawable = typedArray.getResourceId(R.styleable.vericationCodeView_vcv_et_cursor,R.drawable.bg_et_cursor);  
  168.   
  169.         //释放资源  
  170.         typedArray.recycle();  
  171.         initView();  
  172.     }  
  173.   
  174.     @SuppressLint("ResourceAsColor")  
  175.     private void initView() {  
  176.         for (int i = 0; i < mEtNumber; i++) {  
  177.             EditText editText = new EditText(mContext);  
  178.             initEditText(editText, i);  
  179.             addView(editText);  
  180.             if (i == 0) { //设置第一个editText获取焦点,并弹出软键盘  
  181.                 editText.setFocusable(true);  
  182.                 if(mContext instanceof Activity){  
  183.                     ((Activity)mContext).getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);  
  184.                 }  
  185.             }  
  186.         }  
  187.     }  
  188.   
  189.     private void initEditText(EditText editText, int i) {  
  190.         int childHPadding = 0;  
  191.         int childVPadding = 0;  
  192.   
  193.         LayoutParams layoutParams = new LayoutParams(mEtWidth,mEtHeight);  
  194.         layoutParams.bottomMargin = childVPadding;  
  195.         layoutParams.topMargin = childVPadding;  
  196.         layoutParams.leftMargin = childHPadding;  
  197.         layoutParams.rightMargin = childHPadding;  
  198.         layoutParams.gravity = Gravity.CENTER;  
  199.         editText.setLayoutParams(layoutParams);  
  200.         editText.setGravity(Gravity.CENTER);  
  201.         editText.setId(i);  
  202.         editText.setCursorVisible(true);  
  203.         editText.setMaxEms(1);  
  204.         editText.setTextColor(mEtTextColor);  
  205.         editText.setTextSize(mEtTextSize);  
  206.         editText.setMaxLines(1);  
  207.         editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});  
  208.         switch (mEtInputType) {  
  209.             case NUMBER:  
  210.                 editText.setInputType(InputType.TYPE_CLASS_NUMBER);  
  211.                 break;  
  212.             case NUMBERPASSWORD:  
  213.                 editText.setInputType(InputType.TYPE_CLASS_NUMBER|InputType.TYPE_NUMBER_VARIATION_PASSWORD);  
  214.                 break;  
  215.             case TEXT:  
  216.                 editText.setInputType(InputType.TYPE_CLASS_TEXT);  
  217.                 break;  
  218.             case TEXTPASSWORD:  
  219.                 editText.setInputType(InputType.TYPE_CLASS_TEXT|InputType.TYPE_TEXT_VARIATION_PASSWORD);  
  220.                 break;  
  221.             default:  
  222.                 editText.setInputType(InputType.TYPE_CLASS_NUMBER);  
  223.         }  
  224.         editText.setPadding(0000);  
  225.         editText.setOnKeyListener(this);  
  226.         if(mEtTextBg != 0) {  
  227.             editText.setBackgroundResource(mEtTextBg);  
  228.         }  
  229.   
  230.         //修改光标的颜色(反射)  
  231.         try {  
  232.             if(mCursorDrawable != 0) {  
  233.                 Field f = TextView.class.getDeclaredField("mCursorDrawableRes");  
  234.                 f.setAccessible(true);  
  235.                 f.set(editText, mCursorDrawable);  
  236.             }  
  237.         } catch (Exception ignored) {  
  238.         }  
  239.         editText.addTextChangedListener(this);  
  240.         editText.setOnFocusChangeListener(this);  
  241.         editText.setOnKeyListener(this);  
  242.     }  
  243.   
  244.   
  245.     @Override  
  246.     public void beforeTextChanged(CharSequence s, int start, int count, int after) {  
  247.   
  248.     }  
  249.   
  250.     @Override  
  251.     public void onTextChanged(CharSequence s, int start, int before, int count) {  
  252.   
  253.     }  
  254.   
  255.     @Override  
  256.     public void afterTextChanged(Editable s) {  
  257.         if (s.length() != 0) {  
  258.             focus();  
  259.         }  
  260.     }  
  261.   
  262.     @Override  
  263.     public boolean onKey(View v, int keyCode, KeyEvent event) {  
  264.         if (keyCode == KeyEvent.KEYCODE_DEL) {  
  265.             backFocus();  
  266.         }  
  267.         return false;  
  268.     }  
  269.   
  270.     @Override  
  271.     public void setEnabled(boolean enabled) {  
  272.         int childCount = getChildCount();  
  273.         for (int i = 0; i < childCount; i++) {  
  274.             View child = getChildAt(i);  
  275.             child.setEnabled(enabled);  
  276.         }  
  277.     }  
  278.   
  279.     /** 
  280.      * 获取焦点 
  281.      */  
  282.     private void focus() {  
  283.         int count = getChildCount();  
  284.         EditText editText;  
  285.         //利用for循环找出还最前面那个还没被输入字符的EditText,并把焦点移交给它。  
  286.         for (int i = 0; i < count; i++) {  
  287.             editText = (EditText) getChildAt(i);  
  288.             if (editText.getText().length() < 1) {  
  289.                 editText.setCursorVisible(true);  
  290.                 editText.requestFocus();  
  291.                 return;  
  292.             } else {  
  293.                 editText.setCursorVisible(false);  
  294.             }  
  295.         }  
  296.         //如果最后一个输入框有字符,则返回结果  
  297.         EditText lastEditText = (EditText) getChildAt(mEtNumber - 1);  
  298.         if (lastEditText.getText().length() > 0) {  
  299.             getResult();  
  300.         }  
  301.     }  
  302.   
  303.     private void backFocus() {  
  304.         //博主手机不好,经常点一次却触发两次`onKey`事件,就设置了一个防止多点击,间隔100毫秒。  
  305.         long startTime = System.currentTimeMillis();  
  306.         EditText editText;  
  307.         //循环检测有字符的`editText`,把其置空,并获取焦点。  
  308.         for (int i = mEtNumber - 1; i >= 0; i--) {  
  309.             editText = (EditText) getChildAt(i);  
  310.             if (editText.getText().length() >= 1 && startTime - endTime > 100) {  
  311.                 editText.setText("");  
  312.                 editText.setCursorVisible(true);  
  313.                 editText.requestFocus();  
  314.                 endTime = startTime;  
  315.                 return;  
  316.             }  
  317.         }  
  318.     }  
  319.   
  320.     private void getResult() {  
  321.         StringBuffer stringBuffer = new StringBuffer();  
  322.         EditText editText;  
  323.         for (int i = 0; i < mEtNumber; i++) {  
  324.             editText = (EditText) getChildAt(i);  
  325.             stringBuffer.append(editText.getText());  
  326.         }  
  327.         if (onCodeFinishListener != ) {  
  328.             onCodeFinishListener.onComplete(stringBuffer.toString());  
  329.         }  
  330.     }  
  331.   
  332.     @Override  
  333.     public void onFocusChange(View v, boolean hasFocus) {  
  334.         if (hasFocus) {  
  335.             focus();  
  336.         }  
  337.     }  
  338.   
  339.     public interface OnCodeFinishListener {  
  340.         void onComplete(String content);  
  341.     }  
  342. }  

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

[html]  view plain  copy
  1. <!-- 自定义验证码输入框-->  
  2.     <declare-styleable name="vericationCodeView">  
  3.         <!--输入框的数量-->  
  4.         <attr name="vcv_et_number" format="integer" />  
  5.         <!--输入类型-->  
  6.         <attr name="vcv_et_inputType">  
  7.             <enum name="number" value="0" />  
  8.             <enum name="numberPassword" value="1" />  
  9.             <enum name="text" value="2" />  
  10.             <enum name="textPassword" value="3" />  
  11.         </attr>  
  12.         <!--输入框的宽度-->  
  13.         <attr name="vcv_et_width" format="dimension|reference" />  
  14.         <!--输入框的高度-->  
  15.         <attr name="vcv_et_height" format="dimension|reference" />  
  16.         <!--输入框文字颜色-->  
  17.         <attr name="vcv_et_text_color" format="color|reference" />  
  18.         <!--输入框文字大小-->  
  19.         <attr name="vcv_et_text_size" format="dimension|reference" />  
  20.         <!--输入框背景-->  
  21.         <attr name="vcv_et_bg" format="reference" />  
  22.         <!--光标样式-->  
  23.         <attr name="vcv_et_cursor" format="reference" />  
  24.     </declare-styleable>  

3.使用:

xml:

[html]  view plain  copy
  1. <com.shushan.ui.VerificationCodeView  
  2.         android:id="@+id/verification_code_view"  
  3.         android:layout_width="wrap_content"  
  4.         android:layout_height="wrap_content"  
  5.         android:layout_below="@id/rl_already_send_to_phone"  
  6.         android:layout_centerHorizontal="true"  
  7.         android:layout_marginTop="29dp"  
  8.         app:vcv_et_width = "60.5dp"  
  9.         app:vcv_et_height = "56.5dp" />  

Java:

[java]  view plain  copy
  1. private VerificationCodeView mVeriCodeView;  
  2. mVeriCodeView = (VerificationCodeView) findViewById(R.id.verification_code_view);  
  3. mVeriCodeView.setOnCodeFinishListener(this);//验证码输入完毕的回调  

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值