上篇讲到登录注册的流程所需用到的带显示密码的输入框,而在整个完整流程中,短信发送获取验证码并填写相信也是重要的一环。当然,关于验证码的实现很多大神的也写过,并且款式多样,任君选择,这里只是记录一下小弟在开发过程中用到的验证码输入框。
先上图:
要实现的就是中间的那个验证码输入框。
这里我们需要实现的点有: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>