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>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章