Android 验证码输入框的实现

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

  先上图:

                                                                              

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

  这里我们需要实现的点有: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>

 

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值