精华内容
下载资源
问答
  • android 验证码输入框

    2020-05-17 01:15:36
    这里写自定义目录标题验证码输入框器1 开始写布局文件2 开始Activity创建 验证码输入框器 最近在公司做项目的时候,做到了需要用到验证码的地方,因为之前做也没写过,这样的于是在网上百度了一下,发现是五花八门的...

    验证码输入框器

    最近在公司做项目的时候,做到了需要用到验证码的地方,因为之前做也没写过,这样的于是在网上百度了一下,发现是五花八门的,没有找到一个感觉实用的东西,也就自己想办法,用自己的思路做了一个,在这里分享给大家,希望能给同行门一点帮助和思路,看看实际的效果吧!哈哈。
    实际运行效果

    1 开始写布局文件

    首先开始要做的就先将这几个输入验证码的框框做出来,不多说直接上代码吧:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:orientation="horizontal"
            tools:ignore="MissingConstraints">
    
            <EditText
                android:id="@+id/num_in1_et"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:background="@drawable/shape_blue_stroke_5dp"
                android:gravity="center"
                android:inputType="number"
                android:maxLength="1"
                android:textColor="#3AB3CB"
                android:textSize="24sp" />
    
            <EditText
                android:id="@+id/num_in2_et"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_marginLeft="15dp"
                android:background="@drawable/shape_blue_stroke_5dp"
                android:gravity="center"
                android:inputType="number"
                android:maxLength="1"
                android:textColor="#3AB3CB"
                android:textSize="24sp" />
    
            <EditText
                android:id="@+id/num_in3_et"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_marginLeft="15dp"
                android:background="@drawable/shape_blue_stroke_5dp"
                android:gravity="center"
                android:inputType="number"
                android:maxLength="1"
                android:textColor="#3AB3CB"
                android:textSize="24sp" />
    
            <EditText
                android:id="@+id/num_in4_et"
                android:layout_width="45dp"
                android:layout_height="45dp"
                android:layout_marginLeft="15dp"
                android:background="@drawable/shape_blue_stroke_5dp"
                android:gravity="center"
                android:inputType="number"
                android:maxLength="1"
                android:textColor="#3AB3CB"
                android:textSize="24sp" />
    
        </LinearLayout>
    
    </RelativeLayout>
    

    gravity 设置内容位置这里我设置的居中,inputType设置输入的类型,验证码数字
    maxLength设置输入内容的最大长度,textColor,输入文字颜色
    textSize,输入文字大小
    这里我就以四位验证码为示例来写的,当然了,6位也差不了多少,直接在后面加就是了。
    然后就是background资源代码,不多说看图:
    在这里插入图片描述
    创建之后代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <corners android:radius="5dp"/>
        <solid android:color="#ffffff"/>
        <stroke android:width="1dp" android:color="#3DB3CC"/>
    </shape>
    

    corners设置四个边角,solid设置整体背景,stroke设置边框,width设置边框宽度,color颜色

    2 开始Activity创建

    接下来开始的就是我门的重头戏了,在activity中实现我门想要的效果不多说,直接上代码:
    
    package com.example.androidstudydemo;
    
    import androidx.annotation.Nullable;
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.util.Log;
    import android.view.KeyEvent;
    import android.view.View;
    import android.widget.EditText;
    
    public class MainActivity extends AppCompatActivity {
        private EditText num_in1_et, num_in2_et, num_in3_et, num_in4_et;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            num_in1_et = findViewById(R.id.num_in1_et);
            num_in2_et = findViewById(R.id.num_in2_et);
            num_in3_et = findViewById(R.id.num_in3_et);
            num_in4_et = findViewById(R.id.num_in4_et);
    
            //addTextChangedListener设置监听文本变化,有输入跳转到下一个输入框
            num_in1_et.addTextChangedListener(new TextChangeLister(num_in1_et,num_in2_et));
    
            //setOnKeyListener设置监听键盘删除操作,删除完之后跳转到上一个输入框
            num_in2_et.setOnKeyListener(new MyOnKeyListenr(num_in1_et, num_in2_et));
    
            num_in2_et.addTextChangedListener(new TextChangeLister(num_in2_et,num_in3_et));
    
            num_in3_et.setOnKeyListener(new MyOnKeyListenr(num_in2_et, num_in3_et));
            num_in3_et.addTextChangedListener(new TextChangeLister(num_in3_et,num_in4_et));
    
            num_in4_et.setOnKeyListener(new MyOnKeyListenr(num_in3_et, num_in4_et));
        }
    
        //自定义文本变化监听类
    class TextChangeLister implements TextWatcher {
            private EditText thisEt,newxtEt;
            public TextChangeLister(EditText thisEt,EditText newxtEt){
                this.thisEt=thisEt;
                this.newxtEt=newxtEt;
            }
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
    
        }
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            //text 输入框中改变后的字符串信息 
            //start 输入框中改变后的字符串的起始位置 
            //before 输入框中改变前的字符串的位置 默认为0 
            //count 输入框中改变后的一共输入字符串的数量 
            if(before==0&&count==1){
                thisEt.clearFocus();
                newxtEt.requestFocus();
            }
        }
    
        @Override
        public void afterTextChanged(Editable s) {
    
        }
    }
    
        //自定义键盘监听
        class MyOnKeyListenr implements View.OnKeyListener {
            private EditText upDt, thisDt;
    
            public MyOnKeyListenr(@Nullable EditText upDt, @Nullable EditText thisDt) {
                this.upDt = upDt;
                this.thisDt = thisDt;
    
            }
    
            @Override
            public boolean onKey(View view, int i, KeyEvent keyEvent) {
                Log.i("键盘监控", "view:" + view + "   i:" + i + "   keyEvent:" + keyEvent.toString());
                if (keyEvent.getAction() == KeyEvent.ACTION_DOWN && i == KeyEvent.KEYCODE_DEL) {  //如果上一个输入框不为空
                    if (upDt != null && thisDt.getText().toString().isEmpty()) {
                        thisDt.clearFocus();
                        upDt.requestFocus();
                    }
                    return false;
                }
                return false;
            }
        }
    
    }
    
    

    代码的具体详解这里我就不在从新说明了,代码中的注解差不错都已经说的很清楚了,如果实在有不清楚的同学,可以给我留言,我会为之解答的, 这里说说我为什么会这样写的原因吧。
    首先我是想用OnKeyListener监听直接实现的输入框下一个和上一个之间的跳转的,并且都写出来实现了,在模拟器上也能达到想要的效果。可是在真机上出问题了,数值输入的事件OnKeyListener根本就监听不了。之后我又尝试了软键盘监听器,但是使用软件盘监听感觉代码量多一些,最后我使用了输入文本变化监听器addTextChangedListener加上OnKeyListener监听的结合达到了我想要的目的。使用addTextChangedListener监听文本的输入事件,然后跳转到下一个输入框。使用OnKeyListener监听用户的删除事件,跳转到上一个输入框。
    好了,同志门还有什么更好的实现方法,欢迎来交流学习。

    展开全文
  • Android验证码输入框,炫酷的动画
  • Android验证码输入框支持粘贴

    千次阅读 热门讨论 2019-04-04 20:25:11
    验证码输入框,满足剪切板内容自动填充,看效果 原本做法是6个EditText,后来发现,这样写最大问题是,无法满足粘贴功能,验证码短信 一般都带“复制”,如果牺牲掉了验证码粘贴功能 确实有点操蛋。 先聊聊思路: 1...

    验证码输入框,满足剪切板内容自动填充,看效果
    在这里插入图片描述
    原本做法是6个EditText,后来发现,这样写最大问题是,无法满足粘贴功能,验证码短信 一般都带“复制”,点击 短信通知栏 的“复制”后,6位验证码会自动显示在软键盘左上角,点击一下即完成填充。

    如果牺牲掉了验证码“通知栏短信-复制-点击填充”功能 ,用户必须一次性记住6位,逐个输入;若是用户习惯性点击了复制后,发现app竟然无法填充,自己也没记验证码,再次下拉看通知栏看短信时,发现通知栏短信也没了,就必须要回到短信收件箱里查找,这种用户体验,WTF,狠操蛋!!!一定要规避这种打破用户操作习惯,引起用户不爽的细节。

    先聊聊思路:
    1.首先想到 写一个EditText,然后setBackground()为6个框,字间距刚好让每个数字处于框中间;然而字间距的方法没找到合适的,全部是按比例分间距的,累觉不爱,适配是个巨坑,前路艰险,性价比太低,放弃之。
    2.我打开滴滴,美团,结果大厂的复制粘贴各种花式bug啪啪打脸,就不一一拉出来细评了。
    3.功夫不负有心人,终于找到一个支持粘贴的app—建设银行,尽管被我测出了bug,也给我启发,让我看出了端倪。
    在这里插入图片描述

    看到上图我猜想,蓝色水滴中间才是全部编辑框字体,于是我剪切,结果正如我所料,框内字体被清除了,并且无论我如何点击,双击,长按最后一个框,光标始终在第二个框里跳动。
    于是,我有思路了,所有的框就是TextView,而真正的编辑框内容是透明的。为了点击最后一个框也能唤起软键盘,需要让EditText的宽度与六个框一样宽;

    建行app 有个缺点就是 光标可以随着手势左右滑动游走,怎么避免呢,

    • 第一道防线:EditText.setTextSize(0.01f),即便不小心弹出选中操作框,字体足够小,小到可以避免光标随手势左右游走,精度层避免该现象,当然这只是补救措施,根本杜绝的话,需要避免选中操作框弹出;
    • 第二道防线:屏蔽长按事件避免出现“剪切,复制,粘贴”的那个系统选项框;
    • 第三道防线:屏蔽双击事件,经测小米、华为等手机,双击和长按都会弹出“剪切,复制,粘贴”系统选项框,宜将剩勇追穷寇,务必赶尽杀绝。

    实现功能:
    1.点短信复制后,支持剪切板自动填充,即粘贴;
    2.屏蔽长按粘贴,和双击选中;
    3.输入完成回调;
    4.根据屏幕宽度和左右间距 自动适配 输入方框大小

    明显缺点
    此种情况下,无法显示光标,暂时没有想到简单易行的解决办法,如有思路,求评论区赐教。

    上代码吧:

    /**
     * Created by @author iblade.Wang on 2019/4/4.
     * 验证码输入框
     * EditText字号极小,且颜色透明
     */
    
    public class VerCodeInputView extends FrameLayout {
            /**
         * 输入框个数
         */
        private int inputNum;
        /**
         * 输入框宽度
         */
        private int inputWidth;
        private int inputHeight;
        /**
         * 输入框之间的间隔
         */
        private int childPadding;
        /**
         * 输入框背景
         */
        private int editTextBg;
        /**
         * 文本颜色
         */
        private int textColor;
        /**
         * 文本字体大小
         */
        private int textSize;
        /**
         * 输入类型
         */
        private int inputType;
    
    
        public VerCodeInputView(Context context) {
            this(context, null);
        }
    
        public VerCodeInputView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public VerCodeInputView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray ta = context.getTheme().obtainStyledAttributes(attrs, R.styleable.VerCodeInputView, defStyleAttr, 0);
            inputNum = ta.getInteger(R.styleable.VerCodeInputView_inputNum, 6);
            inputWidth = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputWidth, DensityUtil.dip2px(context, 43));
            inputHeight = inputWidth;
            childPadding = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputPadding, DensityUtil.dip2px(context, 7.5f));
            textColor = ta.getColor(R.styleable.VerCodeInputView_inputTxtColor, Color.parseColor("#333333"));
            textSize = ta.getDimensionPixelSize(R.styleable.VerCodeInputView_inputTxtSize, 24);
            editTextBg = ta.getResourceId(R.styleable.VerCodeInputView_inputBg, R.drawable.selector_bg_edit);
            inputType = ta.getInt(R.styleable.VerCodeInputView_inputType, InputType.TYPE_CLASS_NUMBER);
            ta.recycle();
            textViewList = new ArrayList<>(inputNum);
            initViews();
        }
    
        private List<TextView> textViewList;
        private EditText editText;
    
        private void initViews() {
            textViewList.clear();
            //textViewList = new ArrayList<>(inputNum);
            LinearLayout llTextViewRoot = new LinearLayout(getContext());
            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            llTextViewRoot.setLayoutParams(layoutParams);
            llTextViewRoot.setOrientation(LinearLayout.HORIZONTAL);
            addView(llTextViewRoot);
            for (int i = 0; i < inputNum; i++) {
                TextView textView = new TextView(getContext());
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(inputWidth, inputHeight);
                if (i != inputNum - 1) {//最后一个textView 不设置margin
                    params.rightMargin = childPadding;
                }
                params.gravity = Gravity.CENTER;
                textView.setLayoutParams(params);
                textView.setTextColor(textColor);
                textView.setTextSize(textSize);
                textView.setGravity(Gravity.CENTER);
                textView.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
                textView.setInputType(inputType);
                textView.setBackgroundResource(editTextBg);
                if (i == 0) textView.setSelected(true);//默认首个方框选中
                textView.setId(i);
                llTextViewRoot.addView(textView);
                textViewList.add(textView);
            }
            editText = new EditText(getContext());
            LayoutParams layoutParam2 = new LayoutParams(LayoutParams.MATCH_PARENT, inputHeight);
            editText.setLayoutParams(layoutParam2);
            editText.setTextSize(0.01f);
            //设置透明光标,如果直接不显示光标的话,长按粘贴会没效果
            try {
                Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
                f.setAccessible(true);
                f.set(editText, R.drawable.edit_cursor_bg_transparent);
            } catch (Exception e) {
                e.printStackTrace();
            }
            editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputNum)});
            editText.setInputType(inputType);
            editText.setTextColor(ContextCompat.getColor(getContext(), R.color.transparent));
            editText.setBackground(null);
            editText.addTextChangedListener(textWatcher);
            addView(editText);
            initListener();
        }
    
        private void initListener() {
            //屏蔽双击: 好多手机双击会出现 选择 剪切 粘贴 的选项卡,
            new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onDoubleTap(MotionEvent e) {
                    return true;
                }
            });
        }
    
        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 editable) {
                String inputContent = (null == editText.getText()) ? "" : editText.getText().toString();
                //已经有输入时,屏蔽长按和光标
                if (inputContent.length() > 0) {
                    editText.setLongClickable(false);
                    editText.setCursorVisible(false);
                } else {
                    editText.setLongClickable(true);
                    editText.setCursorVisible(true);
                }
                if (listener != null && inputContent.length() >= inputNum) {
                    listener.onComplete(inputContent);
                }
                for (int i = 0, len = textViewList.size(); i < len; i++) {
                    TextView textView = textViewList.get(i);
                    textView.setSelected(false);
                    if (i < inputContent.length()) {
                        textView.setText(String.valueOf(inputContent.charAt(i)));
                    } else {
                        textView.setText("");
                        //选中待输入的textView
                        if (i == inputContent.length()) {
                            textView.setSelected(true);
                        }
                    }
                }
            }
        };
    
        private boolean isAuto = false;
    
        /**
         * 设置宽高自适应,单个框的宽度平分父布局总宽度
         */
        public void setAutoWidth() {
            isAuto = true;
            requestLayout();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = getMeasuredWidth();
            if (isAuto && width > 0) {
                isAuto = false;
                //resetWH(width);
                resetMargin(width);
            }
        }
    
        /*    private void resetWH(int w) {
                int paddings = childPadding * (inputNum - 1);
                inputWidth = (w - paddings) / (inputNum);
                inputHeight = inputWidth;
                for (int i = 0, len = textViewList.size(); i < len; i++) {
                    View child = textViewList.get(i);
                    child.getLayoutParams().height = inputHeight;
                    child.getLayoutParams().width = inputWidth;
                }
                editText.getLayoutParams().height = inputHeight;
            }*/
        private void resetMargin(int width) {
            if (width > 0) {
                int remainWidth = width - (inputNum * inputWidth);
                if (remainWidth > 0 && inputNum > 1) {
                    childPadding = remainWidth / (inputNum - 1);
                    for (int i = 0, len = textViewList.size(); i < len; i++) {
                        View child = textViewList.get(i);
                        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) child.getLayoutParams();
                        if (i != inputNum - 1) {//最后一个textView 不设置margin
                            params.rightMargin = childPadding;
                        }
                        params.gravity = Gravity.CENTER;
                        child.setLayoutParams(params);
                        child.getLayoutParams().height = inputHeight;
                        child.getLayoutParams().width = inputWidth;
                    }
                    editText.getLayoutParams().height = inputHeight;
                }
            }
        }
    
        /**
         * 获取编辑框内容
         *
         * @return 编辑框内容
         */
        public String getEditContent() {
            return editText.getText().toString();
        }
    
        public OnCompleteListener listener;
    
        public void setOnCompleteListener(OnCompleteListener listener) {
            this.listener = listener;
        }
    
        public interface OnCompleteListener {
            /**
             * 完成验证码的填写
             *
             * @param content 填写内容
             */
            void onComplete(String content);
        }
    }
    

    如何调用:

    /**
     * @author YlWang
     */
    public class MainActivity extends AppCompatActivity {
        private VerCodeInputView codeInputCard;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
    
        private void initView() {
            codeInputCard = findViewById(R.id.edit);
            codeInputCard.setAutoWidth();
            codeInputCard.setOnCompleteListener(new VerCodeInputView.OnCompleteListener() {
                @Override
                public void onComplete(String content) {
                    Toast.makeText(MainActivity.this, "您输入了:" + content, Toast.LENGTH_LONG).show();
                }
            });
    
        }
    }
    

    另外,框框背景drawable目录下 bg_edit_vercode.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_selected="true">
            <shape android:shape="rectangle">
                <solid android:color="@color/color_ffffff" />
                <stroke android:width="@dimen/dp_05" android:color="@color/color_00b38a" />
            </shape>
        </item>
        <item android:state_selected="false">
            <shape android:shape="rectangle">
                <solid android:color="@color/color_ffffff" />
                <stroke android:width="@dimen/dp_05" android:color="@color/color_dfdfdf" />
            </shape>
        </item>
    </selector>
    

    ------------------------------2019.4.10更新-----------------------

    经测试Vivo,华为部分机型 不会把复制短信的内容呈现在软键盘上方,复制完之后,想粘贴有两种办法:①需要资深玩家在软键盘里找到粘贴按键(缺点:操作麻烦),②大家习惯的长按出现粘贴;

    然鹅。。。上面代码又把长按屏蔽了。哎~心塞塞!!!
    继续优化:

    我们期待长按后出现这种:
    在这里插入图片描述
    可是一旦不屏蔽长按,恶魔放出了瓶子;
    例如:
    在这里插入图片描述
    有坑警告:为了满足长按出现粘贴,删除editText.setLongClickable(false);,长按了好久了,不出现粘贴;同步代码,Clean,Rebuild,各种大动作,仍然长按无效;
    抱着没啥希望的心态 加上editText.setLongClickable(true)再试一把,果然没希望,还是长按无效。
    在这里插入图片描述
    WHY?

    经测删除editText.setCursorVisible(false);再试,长按终于出粘贴了。

    结论:设置光标不可见时,长按将会无效。

    为了满足长按可用,只好设置光标可见,大不了颜色设成透明的(效果上等同于设置不可见)。

    上图蓝色圆球和一大串操作栏好丑,坚决不能出现,那就不得不动态设置了:
    例如不输入内容时,不屏蔽长按;一旦有了输入内容后,屏蔽长按,设置光标不可见,这样就不会出现了,所以修改后代码是这样的。

        private void initViews() {
            textViewList = new ArrayList<>(inputNum);
            LinearLayout llTextViewRoot = new LinearLayout(getContext());
            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
            llTextViewRoot.setLayoutParams(layoutParams);
            llTextViewRoot.setOrientation(LinearLayout.HORIZONTAL);
            addView(llTextViewRoot);
            for (int i = 0; i < inputNum; i++) {
                TextView textView = new TextView(getContext());
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(inputWidth, inputHeight);
                if (i != inputNum - 1) {//最后一个textView 不设置margin
                    params.rightMargin = childPadding;
                }
                params.gravity = Gravity.CENTER;
                textView.setLayoutParams(params);
                textView.setTextColor(textColor);
                textView.setTextSize(textSize);
                textView.setGravity(Gravity.CENTER);
                textView.setFilters(new InputFilter[]{new InputFilter.LengthFilter(1)});
                textView.setInputType(inputType);
                textView.setBackgroundResource(editTextBg);
                textView.setId(i);
                llTextViewRoot.addView(textView);
                textViewList.add(textView);
            }
            editText = new EditText(getContext());
            LayoutParams layoutParam2 = new LayoutParams(LayoutParams.MATCH_PARENT, inputHeight);
            editText.setLayoutParams(layoutParam2);
            editText.setTextSize(0.01f);
            //设置透明光标,如果直接不显示光标的话,长按粘贴会没效果
            try {
                Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
                f.setAccessible(true);
                f.set(editText, R.drawable.edit_cursor_bg_transparent);
            } catch (Exception e) {
                e.printStackTrace();
            }
            editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(inputNum)});
            editText.setInputType(inputType);
            editText.setTextColor(ContextCompat.getColor(getContext(), R.color.transparent));
            editText.setBackground(null);
            editText.addTextChangedListener(textWatcher);
            addView(editText);
            initListener();
        }
    
     
         @Override
         public void afterTextChanged(Editable editable) {
             String inputContent = (null == editText.getText()) ? "" : editText.getText().toString();
             //已经有输入时,屏蔽长按和光标
             if (inputContent.length() > 0) {
                 editText.setLongClickable(false);
                 editText.setCursorVisible(false);
             } else {
                 editText.setLongClickable(true);
                 editText.setCursorVisible(true);
             }
             if (listener != null && inputContent.length() >= inputNum) {
                 listener.onComplete(inputContent);
             }
             for (int i = 0, len = textViewList.size(); i < len; i++) {
                 TextView textView = textViewList.get(i);
                 if (i < inputContent.length()) {
                     textView.setText(String.valueOf(inputContent.charAt(i)));
                 } else {
                     textView.setText("");
                 }
             }
         }
    

    其中:edit_cursor_bg_transparent.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <size android:width="0.01dp" />
    
        <solid android:color="@android:color/transparent" />
    </shape>
    

    2020.04.26更新,加上了 待输入方框的选中色。效果如下:
    在这里插入图片描述

    最近发现有同行也做了类似需求:https://www.jianshu.com/p/3238a5afc21c

    展开全文
  • 作者丨实例波https://www.jianshu.com/p/3238a5afc21c前言验证码输入框是很多APP必不可少的组件,之前在重构注册登录页面的时候,重新设计了UI,所以不能再简单的用EditText来做了,所以这篇文章将分享一下如何实现...

    640?wx_fmt=gif

    640?wx_fmt=jpeg

    黑客技术点击右侧关注,了解黑客的世界!640?wx_fmt=jpeg

    640?wx_fmt=jpeg

    Linux编程点击右侧关注,免费入门到精通!640?wx_fmt=jpeg
    作者丨实例波
    https://www.jianshu.com/p/3238a5afc21c
    前言

    验证码输入框是很多APP必不可少的组件,之前在重构注册登录页面的时候,重新设计了UI,所以不能再简单的用EditText来做了,所以这篇文章将分享一下如何实现一个常见的验证码输入框。

    正文

    先搂一眼效果吧

    640?wx_fmt=other640?wx_fmt=other

    不要把注意力都放在头顶的那一抹绿上,重点在输入框,可能大多数APP里都是采用6个方框的UI效果,我这里是按照我们设计的要求,用6根横线来划出6个数字的位置。一开始我想的是直接用6个TextView,然后传递焦点的做法,但是发现实现起来有一定的难度。又在网上查了一下,发现比较靠谱的办法是用6个TextView加一个EditText来实现,也按照这个方法去实现了,但是后来在测试的时候就发现了问题:网上给出的实现方式需要监听软键盘的删除按钮

    editText.setOnKeyListener(new OnKeyListener() {
                @Overridepublic boolean onKey(View v, int keyCode, KeyEvent event{if (keyCode == KeyEvent.KEYCODE_DEL
                            && event.getAction() == KeyEvent.ACTION_DOWN) {//TODO:return true;
                    }return false;
                }
            });

    这是一个大家熟知的写法,但是这个监听的方法其实并不靠谱(在安卓原生键盘上就监听不到),因为这个监听是否触发,并没有强制的要求,全看输入法开发者的心情,这是官方文档中的描述:

    Key presses in software keyboards will generally NOT trigger this method, although some may elect to do so in some situations.

    只能输入,不能删除,这可不行啊,用户肯定会骂娘的,我可不想被拿去去祭天什么的…
    于是乎只能想办法在原有的基础上做一些修改,来规避这个问题,最后采用的方案是:采用一个TextView的数组来维护6个TextView,然后藏一个透明的EditTextView在后面用于接收用户输入的内容,再把输入的内容展示到6个TextView上就行了,UI什么的可以自己随意设计。在实现的过程中,遇到的一个关键问题就是:当输入的内容超过6位以后我该如何处理?一开始的方案是通过判断当前输入的位数然后再做相应的处理,网上的方案也是这么实现的,我后来一想,根本用不着这么麻烦,只需要一行属性就能解决这个问题:

    android:maxLength="6"

    只需要在EditText的属性里限制它的最大长度,就不用再去代码里做处理了,直接把EditTextView里的内容完全照搬到TextView上就可以了。
    最终的完整代码如下:

    public class VerifyCodeView extends RelativeLayout {private EditText editText;private TextView[] textViews;private static int MAX = 6;private String inputContent;public VerifyCodeView(Context context) {this(context, null);
        }public VerifyCodeView(Context context, AttributeSet attrs) {this(context, attrs, 0);
        }public VerifyCodeView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
            View.inflate(context, R.layout.view_verify_code, this);
            textViews = new TextView[MAX];
            textViews[0] = (TextView) findViewById(R.id.tv_0);
            textViews[1] = (TextView) findViewById(R.id.tv_1);
            textViews[2] = (TextView) findViewById(R.id.tv_2);
            textViews[3] = (TextView) findViewById(R.id.tv_3);
            textViews[4] = (TextView) findViewById(R.id.tv_4);
            textViews[5] = (TextView) findViewById(R.id.tv_5);
            editText = (EditText) findViewById(R.id.edit_text_view);
            editText.setCursorVisible(false);//隐藏光标
            setEditTextListener();
        }private void setEditTextListener() {
            editText.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                }@Overridepublic void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                }@Overridepublic void afterTextChanged(Editable editable) {
                    inputContent = editText.getText().toString();if (inputCompleteListener != null) {if (inputContent.length() >= MAX) {
                            inputCompleteListener.inputComplete();
                        } else {
                            inputCompleteListener.invalidContent();
                        }
                    }for (int i = 0; i                     if (i                         textViews[i].setText(String.valueOf(inputContent.charAt(i)));
                        } else {
                            textViews[i].setText("");
                        }
                    }
                }
            });
        }private InputCompleteListener inputCompleteListener;public void setInputCompleteListener(InputCompleteListener inputCompleteListener) {this.inputCompleteListener = inputCompleteListener;
        }public interface InputCompleteListener {void inputComplete();void invalidContent();
        }public String getEditContent() {return inputContent;
        }
    }

    经过thisfeng的提醒,发现存在几个问题:

    1.双击和长按会选中EditText的内容,出现复制粘贴等选项

    2.光标位置会随着点击而改变,输入数字可能会插入到中间的位置

    于是做了相应的修改:

    //屏蔽长按事件
    android:longClickable="false"
    使用自定义EditText:public class MyEditText extends AppCompatEditText {private long lastTime = 0;public MyEditText(Context context) {super(context);
        }public MyEditText(Context context, AttributeSet attrs) {super(context, attrs);
        }public MyEditText(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);
        }@Overrideprotected void onSelectionChanged(int selStart, int selEnd) {super.onSelectionChanged(selStart, selEnd);//把光标位置固定在最末this.setSelection(this.getText().length());
        }@Overridepublic boolean onTouchEvent(MotionEvent event) {//屏蔽双击事件switch (event.getAction()) {case MotionEvent.ACTION_DOWN:long currentTime = System.currentTimeMillis();if (currentTime - lastTime 500
    ) {
                        lastTime = currentTime;return true;
                    } else {
                        lastTime = currentTime;
                    }break;
            }return super.onTouchEvent(event);
        }
    }

    如果需要完整的demo,可以访问我的github:

    https://github.com/jb274585381/VerifyCodeViewDemo

    结语

    有时候我们实现一个需求,不光要考虑最终的效果,还要考虑时间成本,能用最简单的方法实现当然是最好的,省下的时间拿来打把昆特牌也是不错的。而且写的代码越少,出错的几率越低嘛,是不是~  好了今天就分享到这里,我要去熬我的西米露了。如有错误,欢迎大家指正。

    【无门槛免费领】

    535G超强程序员编程

    0基础从入门到精通自学视频教程!

    640?wx_fmt=jpeg

    640?wx_fmt=jpeg 640?wx_fmt=jpeg

    640?wx_fmt=jpeg 640?wx_fmt=jpeg 640?wx_fmt=jpeg

    640?wx_fmt=jpeg 640?wx_fmt=jpeg 640?wx_fmt=jpeg

    640?wx_fmt=jpeg 640?wx_fmt=jpeg 640?wx_fmt=jpeg

    640?wx_fmt=jpeg 640?wx_fmt=jpeg 640?wx_fmt=jpeg 640?wx_fmt=jpeg

    640?wx_fmt=png万水千山总是情,点个 “在看” 行不行
    展开全文
  • Android 验证码输入框的实现

    千次阅读 热门讨论 2018-12-10 22:25:41
    上篇博客讲到登录注册的流程所需用到的带显示密码的输入框,而在...当然,关于验证码的实现很多大神的博客也写过,并且款式多样,任君选择,这里只是记录一下小弟在开发过程中用到的验证码输入框。  先上图:  ...

      上篇博客讲到登录注册的流程所需用到的带显示密码的输入框,而在整个完整流程中,短信发送获取验证码并填写相信也是重要的一环。当然,关于验证码的实现很多大神的博客也写过,并且款式多样,任君选择,这里只是记录一下小弟在开发过程中用到的验证码输入框。

      先上图:

                                                                                  

      要实现的就是中间的那个验证码输入框。

      这里我们需要实现的点有:1)EditText的排版布局; 2)EditText的背景框; 3)在自定义View编写时需要对第一个输入框进行焦点获取; 4)当输入完一个框后需要自动对焦下一个输入框

      1.EditText的排版布局

      和之前一样,我们先在布局文件中定义好这四个输入框,然后通过建立自定义View继承自ViewGroup或其子类并传入此布局作为我们的操作的View。

      注意:这里由于每个验证码框仅能输入一位,所以我们在布局里对每一个EditText控件都要有最大长度的属性要求。

                             

      2.EditText的背景框

       相信大家对drawable目录下的各种drawable文件都玩的得心应手了,小弟想着代码量不多,并没有对焦点是否对焦的状态分开来写,而是直接写在了selector下,以减少操作量。

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_focused="true">
            <layer-list>
                <item>
                    <shape>
                        <solid android:color="#c6defdff" />
                        <corners android:radius="30dp" />
                    </shape>
                </item>
                <item android:left="5dp" android:top="5dp"
                    android:bottom="5dp" android:right="5dp">
                    <shape>
                        <solid android:color="@android:color/white" />
                        <corners android:radius="12dp" />
                        <stroke android:color="@color/colorAccent"
                            android:width="1dp" />
                    </shape>
                </item>
            </layer-list>
        </item>
        <item android:state_focused="false">
            <layer-list>
                <item>
                    <shape>
                        <solid android:color="#26ededed" />
                        <corners android:radius="30dp" />
                    </shape>
                </item>
                <item android:left="5dp" android:top="5dp"
                    android:right="5dp" android:bottom="5dp">
                    <shape>
                        <solid android:color="@android:color/white" />
                        <corners android:radius="12dp" />
                        <stroke android:color="#43cccccc"
                            android:width="1dp" />
                    </shape>
                </item>
            </layer-list>
        </item>
    </selector>

      这里我用layer-list作了一个小阴影效果,以看起来有小小的层次感。然后对边界作了圆弧化。

      3.View的编写

      这里我们需要将第一个EditText自动获取其焦点。即:

    first.setFocusable(true);
    first.setFocusableInTouchMode(true);

      如果需要软键盘自动弹出,我们可以定义一个InputMethodManager来控制软键盘的弹出与收起,不过在某些机型上貌似有点问题,所以可以在manifest文件中对应的activity标签下添加属性:

    android:windowSoftInputMode="stateVisible|adjustResize"

      然后我们就要对输入过的文本框进行焦点清除,并获取下一个EditText的焦点。

    private void focus() {
        EditText editText;
        //利用for循环找出前面还没被输入字符的EditText
        for (int i = 0; i < mEdits.size(); i++) {
            editText = mEdits.get(i);
            if (editText.getText().length() < 1) {
                editText.requestFocus();
                return;
            } else {
                editText.setCursorVisible(false);
            }
        }
        EditText lastEditText = mEdits.get(mEdits.size() - 1);
        if (lastEditText.getText().length() > 0) {
            //收起软键盘 并不允许编辑 同时将输入的文本提交
            getResponse();
            lastEditText.setCursorVisible(false);
            InputMethodManager imm = (InputMethodManager) getContext()
                    .getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

      这里通过循环去找到前面还没有被输入过的文本框,若存在,则对其进行焦点获取(将此方法用于TextWatcher中监听每个输入框的输入事件,则可以实现自动获取下一个EditText的焦点);否则进行文本提交。

      完整代码:

    package com.example.carson.myapplicationtesting;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.support.annotation.Nullable;
    import android.text.Editable;
    import android.text.TextUtils;
    import android.text.TextWatcher;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.EditText;
    import android.widget.RelativeLayout;
    
    import java.util.ArrayList;
    
    import com.example.carson.myapplicationtesting.R;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by 84594 on 2018/7/30.
     */
    
    public class CodeView extends RelativeLayout implements View.OnFocusChangeListener {
    
        //设验证码有4位
        private EditText first, second, third, fourth;
    
        private OnInputFinishListener mInputListener;
    
        private List<EditText> mEdits = new ArrayList<EditText>();
    
        public CodeView(Context context) {
            this(context, null);
        }
    
        public CodeView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initView();
        }
    
        private void initView() {
            LayoutInflater.from(getContext()).inflate(R.layout.layout_code, this, true);
            first = findViewById(R.id.edit_first);
            second = findViewById(R.id.edit_second);
            third = findViewById(R.id.edit_third);
            fourth = findViewById(R.id.edit_fourth);
    
            mEdits.add(first);
            mEdits.add(second);
            mEdits.add(third);
            mEdits.add(fourth);
    
            first.setFocusable(true);
            first.addTextChangedListener(new MyTextWatcher());
            second.addTextChangedListener(new MyTextWatcher());
            third.addTextChangedListener(new MyTextWatcher());
            fourth.addTextChangedListener(new MyTextWatcher());
    
            first.setOnFocusChangeListener(this);
            second.setOnFocusChangeListener(this);
            third.setOnFocusChangeListener(this);
            fourth.setOnFocusChangeListener(this);
        }
    
        @Override
        public void setEnabled(boolean enabled) {
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i ++) {
                View child = getChildAt(i);
                child.setEnabled(enabled);
            }
        }
    
        @Override
        public void onFocusChange(View view, boolean focus) {
            if (focus) {
                focus();
            }
        }
    
        public void setmInputListener(OnInputFinishListener mInputListener) {
            this.mInputListener = mInputListener;
        }
    
        private class MyTextWatcher implements TextWatcher {
    
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }
    
            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
            }
    
            @Override
            public void afterTextChanged(Editable editable) {
                if (editable.length() != 0) {
                    focus();
                }
            }
        }
        private void focus() {
            EditText editText;
            //利用for循环找出前面还没被输入字符的EditText
            for (int i = 0; i < mEdits.size(); i++) {
                editText = mEdits.get(i);
                if (editText.getText().length() < 1) {
                    editText.requestFocus();
    
                    return;
                } else {
                    editText.setCursorVisible(false);
                }
            }
            EditText lastEditText = mEdits.get(mEdits.size() - 1);
            if (lastEditText.getText().length() > 0) {
                //收起软键盘 并不允许编辑 同时将输入的文本提交
                getResponse();
                lastEditText.setCursorVisible(false);
                InputMethodManager imm = (InputMethodManager) getContext()
                        .getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
            }
        }
    
        public void getResponse() {
            Log.e("CodeView", "ok");
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < mEdits.size(); i++) {
                sb.append(mEdits.get(i).getText().toString());
            }
            if (mInputListener != null) {
                mInputListener.onFinish(sb.toString());
            }
        }
    
        //对外封装一个重置或直接填写验证码的方法
        public void setText(String text) {
            if (text.length() == mEdits.size()) {
                StringBuilder sb = new StringBuilder(text);
                first.setText(sb.substring(0, 1));
                second.setText(sb.substring(1, 2));
                third.setText(sb.substring(2, 3));
                fourth.setText(sb.substring(3, 4));
            } else {
                first.setText("");
                second.setText("");
                third.setText("");
                fourth.setText("");
    //            first.setCursorVisible(true);
                first.requestFocus();
            }
        }
    
        //一个监听输入结束的接口,以便外部回调结束后执行的方法
        public interface OnInputFinishListener {
            void onFinish(String code);
        }
    }
    
    

      布局:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:gravity="center">
    
            <EditText
                android:id="@+id/edit_first"
                android:layout_width="0dp"
                android:layout_height="70dp"
                android:layout_weight="1"
                android:inputType="number"
                android:textSize="40sp"
                android:maxLength="1"
                android:textCursorDrawable="@null"
                android:textColor="@color/colorAccent"
                android:textAlignment="center"
                android:background="@drawable/selector_code_edit"
                android:layout_margin="5dp"/>
            <EditText
                android:id="@+id/edit_second"
                android:layout_width="0dp"
                android:layout_height="70dp"
                android:layout_weight="1"
                android:inputType="number"
                android:textSize="40sp"
                android:maxLength="1"
                android:textColor="@color/colorAccent"
                android:textCursorDrawable="@null"
                android:textAlignment="center"
                android:background="@drawable/selector_code_edit"
                android:layout_margin="5dp"/>
    
            <EditText
                android:id="@+id/edit_third"
                android:layout_width="0dp"
                android:layout_height="70dp"
                android:layout_weight="1"
                android:inputType="number"
                android:textSize="40sp"
                android:maxLength="1"
                android:textColor="@color/colorAccent"
                android:textCursorDrawable="@null"
                android:textAlignment="center"
                android:background="@drawable/selector_code_edit"
                android:layout_margin="5dp"/>
            <EditText
                android:id="@+id/edit_fourth"
                android:layout_width="0dp"
                android:layout_height="70dp"
                android:layout_weight="1"
                android:inputType="number"
                android:textSize="40sp"
                android:maxLength="1"
                android:textColor="@color/colorAccent"
                android:textCursorDrawable="@null"
                android:textAlignment="center"
                android:background="@drawable/selector_code_edit"
                android:layout_margin="5dp"/>
        </LinearLayout>
    
    
    </RelativeLayout>

     

    展开全文
  • mMaxLength = attrs.getAttributeIntValue(XML_NAMESPACE_ANDROID, "maxLength", DEFAULT_TEXT_LENGTH); mNumChars = mMaxLength; // 获取输入框文字高度 getPaint().getTextBounds("|", 0, 1, mTextHeight); ...
  • Android验证码输入框的实现!!!

    千次阅读 2019-05-22 19:53:48
    验证码输入框是很多APP必不可少的组件,之前在重构注册登录页面的时候,重新设计了UI,所以不能再简单的用EditText来做了,所以这篇文章将分享一下如何实现一个常见的验证码输入框。 正文 重点在输入框,可能...
  •  验证码输入框,中间灰色竖线分割。输入信息变化之后再输入框的下方绘制蓝色线条。  当四个字符输入之后,边框实现贪食蛇的滚动效果以达到当前正在进行验证码的校验功能。 2.思路  自定义View 添加四个...
  • 盗个别人的效果图 我的这个控件实现了可以动态配置4位 或者6位 多位的验证码 支持在layout里面动态配置 public class Verificationcode extends RelativeLayout { private Context context; private ...
  • android { compileOptions{ sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } dependencies { implementation 'com.github.Wynsbin:Verif...
  • 这是一个自定义的验证码输入框并且运用到了软件盘的显示和隐藏。
  • 本文实例为大家分享了Android自定义View验证码输入框的具体代码,供大家参考,具体内容如下 验证码输入框 1.先看下样式 2.直接上代码 public class MyVcode extends AppCompatEditText { private int mFigures = ...
  • 简介: Android 自定义方形输入框,仿滴滴验证码输入框 更多:作者提 Bug 标签: Android自定义方形输入框,仿滴滴验证码、小篮单车验证码输入框 V1.0.1 版 效果图 fix bug:验证码输入错误清空输入框 #7...
  • Android 手机验证码输入框

    千次阅读 2019-04-09 14:05:18
    Kotlin-VerificationView VerificationView-手机验证码输入框 Usage Gradle Project level build.gradle buildscript { ext.kotlin_version = '1.3.21' } ... allprojects { repositories { maven { url '...
  • 接上篇https://blog.csdn.net/qq_35605213/article/details/82691871,... "space" //每个输入框之间的间距; "strokeWidth" //边框的高度; "checkedColor" //已输入的颜色 "defaultColor" //未输入的默认颜...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 220
精华内容 88
关键字:

android验证码输入框