美文网首页Android开发Android开发经验谈Android进阶之路
android 中 自己实现验证码表格填写的效果

android 中 自己实现验证码表格填写的效果

作者: 追梦小乐 | 来源:发表于2018-06-05 11:20 被阅读92次

    项目中,遇到了这样要求:实现6位验证码填写的效果,验证码是数字,输入一个后自动跳转到下一个,然后可以删除回退,界面效果如下所示:

    image.png

    特别说明

    没有使用第三方开源库,这可能是比较烦琐的一种原始的实现方法,也没有特意去封装使用,主要理解一下实现思路即可,实现方式应该有很多种,思路其实很重要的。

    实现原理

    其实是比较简单的,每一个验证码号都是一个EditText,当一个输入完成,通过判断字段的长度,看看可输入的长度是不是为1,是的话然后让下一个EditText获取焦点,以此类推,然后对EditText进行各种监听管理:例如删除、删除回退、是否是最后一个等等

    核心代码实现

    将验证码的6个EditText添加到集合中管理,默认第一个获取焦点


    image.png
    image.png
    image.png

    对EditText进行监听处理


    image.png
    image.png
    image.png
    image.png
    image.png

    完整代码如下

    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"
        style="@style/style_match_parent_white_bg"
        android:id="@+id/rootview"
        tools:context="com.tecsun.tsb.tosharetreasure.activity.login.VerificationCodeActivity">
    
        <include
            android:id="@+id/llt_toolbar"
            layout="@layout/layout_genal_tool_bar"/>
    
        <LinearLayout
            android:layout_below="@id/llt_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            >
    
            <TextView
                android:layout_marginTop="20dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="验证码短信已经发送至:"
                android:textColor="@color/black"
                android:layout_gravity="center"
                />
    
            <TextView
                android:id="@+id/tv_phone_num"
                android:layout_marginTop="5dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                tools:text="1380013800"
                android:textColor="@color/c_000000"
                android:layout_gravity="center"
                />
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                >
    
                <TextView
                    android:id="@+id/textView2"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"/>
    
                <EditText
                    android:id="@+id/et_num_one"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <EditText
                    android:id="@+id/et_num_two"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <EditText
                    android:id="@+id/et_num_three"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <EditText
                    android:id="@+id/et_num_four"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <EditText
                    android:id="@+id/et_num_five"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <EditText
                    android:id="@+id/et_num_six"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:background="@null"
                    android:padding="@dimen/dp_4"
                    android:layout_weight="1"
                    android:maxLength="1"
                    android:textColor="@color/black"
                    android:gravity="center"
                    android:inputType="number"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    />
    
            </LinearLayout>
    
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:orientation="horizontal"
                >
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="0.5"
                    />
    
                <View
                    android:layout_width="0dp"
                    android:layout_height="1dp"
                    android:background="@color/black"
                    android:layout_weight="1"
                    />
    
                <TextView
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="2"
                    />
    
            </LinearLayout>
    
        </LinearLayout>
    
    
        <Button
            android:layout_alignParentBottom="true"
            android:id="@+id/bt_start"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="开启旅程"
            android:textColor="@android:color/white"
            android:background="@color/c_blue_2"
            />
    
    </RelativeLayout>
    

    2、界面实现逻辑

    /**
     * 验证码页面
     */
    public class VerificationCodeActivity extends BaseActivity {
    
        private static final String TAG = VerificationCodeActivity.class.getSimpleName();
        @BindView(R.id.common_titleBar_iv_back)
        ImageView commonTitleBarIvBack;
        @BindView(R.id.common_titleBar_tv_title)
        TextView commonTitleBarTvTitle;
        @BindView(R.id.tv_phone_num)
        TextView tvPhoneNum;
        @BindView(R.id.textView2)
        TextView textView2;
        @BindView(R.id.et_num_one)
        EditText etNumOne;
        @BindView(R.id.et_num_two)
        EditText etNumTwo;
        @BindView(R.id.et_num_three)
        EditText etNumThree;
        @BindView(R.id.et_num_four)
        EditText etNumFour;
        @BindView(R.id.bt_start)
        Button btStart;
    
        @BindView(R.id.rootview)
        View mRootView;
        @BindView(R.id.et_num_five)
        EditText etNumFive;
        @BindView(R.id.et_num_six)
        EditText etNumSix;
    
        private int mFlag;
        private boolean mIsRegist;
        private String mPhoneNum;
    
        private ArrayList<EditText> etLists = new ArrayList<>();
    
        private SystemInfoBean mSystemInfoBean;
    
        private LatitudeAndLongitudeBean mLatitudeAndLongitudeBean;
    
        private String mLoginLatitude;
        private String mLoginLongitude;
    
        @Override
        public int setLayout() {
            return R.layout.activity_verification_code;
        }
    
        @Override
        public void init() {
            initData();
            initListener();
            initOperation();
        }
    
        /**
         * 初始化数据的方法
         */
        private void initData() {
            commonTitleBarTvTitle.setText("填写验证码");
            Intent intent = getIntent();
            if (intent != null) {
                mFlag = intent.getIntExtra(Constants.ACTIVITY_PAGE_FLAG, 0);
                mIsRegist = intent.getBooleanExtra(Constants.ISREGIST, false);
                mPhoneNum = intent.getStringExtra(Constants.PHONE_NUM);
    
                mSystemInfoBean = (SystemInfoBean)intent.getSerializableExtra(SYSTEM_INFO);
                if (mSystemInfoBean != null){
                    mLatitudeAndLongitudeBean = mSystemInfoBean
                            .mLatitudeAndLongitudeBean;
                    if (mLatitudeAndLongitudeBean != null){
                        mLoginLatitude = mLatitudeAndLongitudeBean.loginLatitude;
                        mLoginLongitude = mLatitudeAndLongitudeBean.loginLongitude;
                    }
                }
    
                if (!TextUtils.isEmpty(mPhoneNum)) {
                    tvPhoneNum.setText("+86  " + mPhoneNum);
                }
            }
    
            etLists.clear();
    
            etLists.add(etNumOne);
            etLists.add(etNumTwo);
            etLists.add(etNumThree);
            etLists.add(etNumFour);
            etLists.add(etNumFive);
            etLists.add(etNumSix);
    
            showInputManager(etNumOne);
        }
    
        private void showInputManager(EditText editText) {
            editText.setFocusable(true);
            editText.setFocusableInTouchMode(true);
            editText.requestFocus();
    
            /** 目前测试来看,还是挺准的
             * 原理:OnGlobalLayoutListener 每次布局变化时都会调用
             * 界面view 显示消失都会调用,软键盘显示与消失时都调用
             * */
            mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutChangeListener);
            InputMethodManager inputManager =
                    (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
    
        }
    
        public void showSoftInput(EditText input) {
            input.setFocusable(true);
            input.requestFocus();
            InputMethodManager inputMethodManager = (InputMethodManager) mContext.getSystemService
                    (Context.INPUT_METHOD_SERVICE);
            inputMethodManager.showSoftInput(input, InputMethodManager.SHOW_IMPLICIT);
        }
    
    
        /**
         * 初始化监听的方法
         */
        private void initListener() {
            editTextListener(etNumOne, etNumTwo);
            editTextListener(etNumTwo, etNumThree);
            editTextListener(etNumThree, etNumFour);
            editTextListener(etNumFour, etNumFive);
            editTextListener(etNumFive, etNumSix);
        }
    
        /**
         * 初始化操作的方法
         */
         private void initOperation() {
             if (!TextUtils.isEmpty(mPhoneNum)){
                 send(mPhoneNum, "1");
             }
         }
    
        @OnClick({R.id.common_titleBar_iv_back, R.id.bt_start})
        public void onViewClicked(View view) {
            switch (view.getId()) {
                case R.id.common_titleBar_iv_back:
                    finish();
                    break;
                case R.id.bt_start:
    
                    String codeValue = getCodeValue(etLists);
                    if (!TextUtils.isEmpty(codeValue)){
                        boolean isCodeValue = isCodeValue(codeValue);
                        if (isCodeValue){
                            codePast(mPhoneNum);
                        }
                    }else {
                        ToastUtil.toast(mContext,"验证码不能为空");
                    }
                    break;
            }
        }
    
        /**
         * 通过flag来区分是跳转到修改密码还是完善资料
         *
         * @param flag
         */
        private void checkAction(int flag) {
            switch (flag) {
                case Constants.FORGET_TO_VERIFICATIONCODE:
                    goToResetPassword();
                    break;
                case Constants.REGIST_TO_PERFECT:
                    goToPerfectData();
                    break;
            }
        }
    
        /**
         * 前往信息完善页面
         */
        private void goToPerfectData() {
            Intent intent = new Intent(mContext,PerfectDataActivity.class);
            intent.putExtra(SYSTEM_INFO,mSystemInfoBean);
            startActivity(intent);
            finish();
        }
    
        /**
         * 从忘记密码的流程过来,前往重设密码的界面
         */
        private void goToResetPassword() {
            Intent intent = new Intent(mContext,ChangePwdActivity.class);
            intent.putExtra(SYSTEM_INFO,mSystemInfoBean);
            startActivity(intent);
            finish();
        }
    
        /**
         * 4个EditText自动切换
         */
        private void autoMoveEdit(EditText firstEditText, EditText twoEditText) {
            if (firstEditText.isFocused()) {
                LogUtils.d(TAG, "autoMoveEdit======");
                String oneCode = firstEditText.getText().toString();
                firstEditText.setSelection(oneCode.length());
                if (oneCode.length() == 1) {
                    setFocu(firstEditText, twoEditText);
                }
            }
        }
    
    
        /**
         * 设置焦点
         */
        private void setFocu(EditText beforeEt, EditText pEt) {
            pEt.setFocusable(true);
            pEt.setFocusableInTouchMode(true);
            pEt.requestFocus();
            pEt.setSelection(pEt.getText().toString().trim().length());
            delFocu(beforeEt, pEt);
        }
    
        /**
         * 监听软键盘的删除键,删除
         *
         * @param beforeEt
         * @param nextEt
         */
        private void delFocu(final EditText beforeEt, final EditText nextEt) {
            nextEt.setOnKeyListener(new View.OnKeyListener() {
                @Override
                public boolean onKey(View v, int keyCode, KeyEvent event) {
                    if (nextEt.equals(etLists.get(0))) {
                        return true;
                    }
                    String s = beforeEt.getText().toString();
                    LogUtils.d(TAG, "delFocu============s============" + s);
                    if (!TextUtils.isEmpty(s)) {
                        beforeEt.setText("");
                        beforeEt.setFocusable(true);
                        beforeEt.setFocusableInTouchMode(true);
                        beforeEt.requestFocus();
                    }
                    return false;
                }
            });
        }
    
    
        /**
         * 对EditText监听
         *
         * @param beforeEdit
         * @param afterEdit
         */
        private void editTextListener(final EditText beforeEdit, final EditText afterEdit) {
            beforeEdit.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    LogUtils.d(TAG, "beforeTextChanged======");
                }
    
                @Override
                public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    LogUtils.d(TAG, "onTextChanged======");
                    autoMoveEdit(beforeEdit, afterEdit);
                }
    
                @Override
                public void afterTextChanged(Editable editable) {
    
                }
            });
        }
    
        /**
         * 获取手动输入的验证码的值
         */
        private String getCodeValue(ArrayList<EditText> list){
            StringBuilder sb = new StringBuilder();
            if (list != null){
                int size = list.size();
                if (size > 0){
                    for (int i = 0; i < size; i++) {
                        EditText editText = list.get(i);
                        String s = editText.getText().toString();
                        if (!TextUtils.isEmpty(s)){
                            sb.append(s);
                        }
    
                    }
                }
            }
            return sb.toString();
        }
    
    
        /**
         * 判断有没有输入6位验证码
         */
        private boolean isCodeValue(String codeValue){
            int length = codeValue.length();
            if (length == 6){
    
                return  true;
            }else {
                return  false;
            }
    
        }
    
        ViewTreeObserver.OnGlobalLayoutListener mLayoutChangeListener = new ViewTreeObserver
                .OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //判断窗口可见区域大小
                Rect r = new Rect();
                // getWindowVisibleDisplayFrame()会返回窗口的可见区域高度
                getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                //如果屏幕高度和Window可见区域高度差值大于整个屏幕高度的1/3,则表示软键盘显示中,否则软键盘为隐藏状态。
                int heightDifference = WindowManagerUtils.getScreenHight() - (r.bottom);
                boolean isKeyboardShowing = heightDifference > WindowManagerUtils.getScreenHight() / 3;
                if (isKeyboardShowing) {
    //                D.i("slack","show..."+ r.bottom + " - " + r.top + " = " + (r.bottom - r.top)
    // +","+ heightDifference);
                    // bottomView 需要跟随软键盘移动的布局
                    // setDuration(0) 默认300, 设置 0 ,表示动画执行时间为0,没有过程,只有动画结果了
                    btStart.animate().translationY(-heightDifference).setDuration(0).start();
                } else {
    //                D.i("slack","hide...");
                    btStart.animate().translationY(0).start();
                }
            }
        };
    
        /**
         * 短信发送接口
         */
        private void send(String phone, String type){
            SendParam param = new SendParam(phone,type);
            AppRequestImpl.getInstance( ).send(phone,type,new ProgressSubscriber<ReplyBaseResultBean<String>>(mContext,getString(R.string.tip_is_send_code), new SubscriberResultListener() {
                @Override
                public void onNext(Object o) {
                    ReplyBaseResultBean<String> bean = (ReplyBaseResultBean<String>) o;
                    loadSendData( bean );
                }
    
                @Override
                public void onErr(Throwable e) {
    //                showWarningDialog(R.string.tip_network_error);
                }
            }) );
        }
    
        /**
         * 处理发送短信数据
         * @param bean
         */
        protected void loadSendData(ReplyBaseResultBean<String> bean ){
            if ( bean == null ){
                return;
            }
            String result = bean.result;
    
    
            if (bean.isSuccess()){
                ToastUtil.toast(mContext,"验证码已发送,请注意查收!");
            }else {
                if (!TextUtils.isEmpty(result)){
                    ToastUtil.toast(mContext,result);
                }
            }
        }
    
        /**
         * 短信验证码是否过期
         */
        private void codePast(String phone){
            CodePastParam param = new CodePastParam(phone);
            AppRequestImpl.getInstance( ).codePast(param,new ProgressSubscriber<CodePastBean>(mContext,getString(R.string.tip_is_code_past), new SubscriberResultListener() {
                @Override
                public void onNext(Object o) {
                    CodePastBean bean = (CodePastBean) o;
                    loadCodePastData( bean );
                }
    
                @Override
                public void onErr(Throwable e) {
    //                showWarningDialog(R.string.tip_network_error);
                }
            }) );
        }
    
        /**
         * 处理验证码有效期数据
         * @param bean
         */
        protected void loadCodePastData(CodePastBean bean ){
            if ( bean == null ){
                return;
            }
            boolean past = bean.past;
    
            if (past){   //验证码有效,前往完善信息的页面
                checkAction(mFlag);
            }else {     //重新请求发送验证码
                initOperation();
            }
        }
    
    }
    
    

    相关文章

      网友评论

      本文标题:android 中 自己实现验证码表格填写的效果

      本文链接:https://www.haomeiwen.com/subject/zfrpsftx.html