上篇博客講到登錄註冊的流程所需用到的帶顯示密碼的輸入框,而在整個完整流程中,短信發送獲取驗證碼並填寫相信也是重要的一環。當然,關於驗證碼的實現很多大神的博客也寫過,並且款式多樣,任君選擇,這裏只是記錄一下小弟在開發過程中用到的驗證碼輸入框。
先上圖:
要實現的就是中間的那個驗證碼輸入框。
這裏我們需要實現的點有: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>