第一次在简书上码文章,主要是记录下以后可能会用到的代码,自用顺便提供给可能需要的同学。
一、需求背景
产品经理突然要求更改短信验证码的样式,觉得验证码输入太过于简单,已经落后市场上其他竞品了,效果图如下:
输入满6位,自动调用接口去验证输入是否正确。验证错误后,验证码变红并提醒用户。允许用户进行删除。
二、简单思路及实现方案
本来是准备使用6个Edittext进行操作,后来研究发现焦点的传递和删除时,处理逻辑过于复杂,后决定使用1个Edittext+6个Textview进行实现,虽然好像感觉有点low,但最快最简单实现不才是我想要的么?直接上代码吧。
1.自定义输入布局(verification_code_layout.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="233dp"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/ll_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_code1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:textSize="30dp"
android:background="@null"
android:gravity="center"/>
<View
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF" />
</LinearLayout>
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="9dp">
<TextView
android:id="@+id/tv_code2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:textSize="30dp"
android:background="@null"
android:gravity="center"/>
<View
android:id="@+id/v2"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF"/>
</LinearLayout>
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="9dp">
<TextView
android:id="@+id/tv_code3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:textSize="30dp"
android:background="@null"
android:gravity="center"/>
<View
android:id="@+id/v3"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF" />
</LinearLayout>
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="35dp">
<TextView
android:id="@+id/tv_code4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:background="@null"
android:textSize="30dp"
android:gravity="center"/>
<View
android:id="@+id/v4"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF" />
</LinearLayout>
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="9dp">
<TextView
android:id="@+id/tv_code5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:background="@null"
android:textSize="30dp"
android:gravity="center"/>
<View
android:id="@+id/v5"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF" />
</LinearLayout>
<LinearLayout
android:layout_width="27dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="9dp">
<TextView
android:id="@+id/tv_code6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#FF303030"
android:background="@null"
android:textSize="30dp"
android:gravity="center"/>
<View
android:id="@+id/v6"
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_marginTop="6dp"
android:background="#FFEFEFEF" />
</LinearLayout>
<EditText
android:id="@+id/et_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/ll_code"
android:layout_alignBottom="@+id/ll_code"
android:background="@android:color/transparent"
android:textColor="@android:color/transparent"
android:cursorVisible="false"
android:inputType="number"/>
</RelativeLayout>
自定义控件代码实现
import android.content.Context;
import android.graphics.Color;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* 6位验证码控件实现
*/
public class VerificationCodeViewextends RelativeLayout {
private Context context;
private TextView tv_code1;
private TextView tv_code2;
private TextView tv_code3;
private TextView tv_code4;
private TextView tv_code5;
private TextView tv_code6;
private View v1;
private View v2;
private View v3;
private View v4;
private View v5;
private View v6;
private EditTextet_code;
private Listcodes =new ArrayList<>();
private InputMethodManagerimm;
public VerificationCodeView(Context context) {
super(context);
this.context = context;
loadView();
}
public VerificationCodeView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
loadView();
}
public VerificationCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
loadView();
}
private void loadView(){
imm = (InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
View view = LayoutInflater.from(context).inflate(R.layout.verification_code_layout, this);
initView(view);
initEvent();
}
private void initView(View view){
tv_code1 = (TextView) view.findViewById(R.id.tv_code1);
tv_code2 = (TextView) view.findViewById(R.id.tv_code2);
tv_code3 = (TextView) view.findViewById(R.id.tv_code3);
tv_code4 = (TextView) view.findViewById(R.id.tv_code4);
tv_code5 = (TextView) view.findViewById(R.id.tv_code5);
tv_code6 = (TextView) view.findViewById(R.id.tv_code6);
et_code = (EditText) view.findViewById(R.id.et_code);
v1 = view.findViewById(R.id.v1);
v2 = view.findViewById(R.id.v2);
v3 = view.findViewById(R.id.v3);
v4 = view.findViewById(R.id.v4);
v5 = view.findViewById(R.id.v5);
v6 = view.findViewById(R.id.v6);
}
private void initEvent(){
//验证码输入
et_code.addTextChangedListener(new 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 !=null && editable.length()>0) {
et_code.setText("");
if(codes.size() <6){
codes.add(editable.toString());
showCode();
}
}
}
});
// 监听验证码删除按键
et_code.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View view, int keyCode, KeyEvent keyEvent) {
if (keyCode == KeyEvent.KEYCODE_DEL && keyEvent.getAction() == KeyEvent.ACTION_DOWN &&codes.size()>0) {
codes.remove(codes.size()-1);
showCode();
//删除时重置textview的颜色
resetTvColor();
return true;
}
return false;
}
});
}
/**
* 显示输入的验证码
*/
private void showCode(){
String code1 ="";
String code2 ="";
String code3 ="";
String code4 ="";
String code5 ="";
String code6 ="";
if(codes.size()>=1){
code1 =codes.get(0);
}
if(codes.size()>=2){
code2 =codes.get(1);
}
if(codes.size()>=3){
code3 =codes.get(2);
}
if(codes.size()>=4){
code4 =codes.get(3);
}
if (codes.size()>=5){
code5 =codes.get(4);
}
if (codes.size()>=6){
code6 =codes.get(5);
}
tv_code1.setText(code1);
tv_code2.setText(code2);
tv_code3.setText(code3);
tv_code4.setText(code4);
tv_code5.setText(code5);
tv_code6.setText(code6);
// setColor();//设置高亮颜色
callBack();//回调
}
/**
* 错误时设置红色
*/
public void setErrorRedColor(){
tv_code1.setTextColor(getResources().getColor(R.color.red_0xFD4440));
tv_code2.setTextColor(getResources().getColor(R.color.red_0xFD4440));
tv_code3.setTextColor(getResources().getColor(R.color.red_0xFD4440));
tv_code4.setTextColor(getResources().getColor(R.color.red_0xFD4440));
tv_code5.setTextColor(getResources().getColor(R.color.red_0xFD4440));
tv_code6.setTextColor(getResources().getColor(R.color.red_0xFD4440));
}
/**
* 重置textview的颜色
*/
public void resetTvColor(){
tv_code1.setTextColor(getResources().getColor(R.color.color_303030));
tv_code2.setTextColor(getResources().getColor(R.color.color_303030));
tv_code3.setTextColor(getResources().getColor(R.color.color_303030));
tv_code4.setTextColor(getResources().getColor(R.color.color_303030));
tv_code5.setTextColor(getResources().getColor(R.color.color_303030));
tv_code6.setTextColor(getResources().getColor(R.color.color_303030));
}
/**
* 回调
*/
private void callBack(){
if(onInputListener==null){
return;
}
if(codes.size()==6){
onInputListener.onSucess(getPhoneCode());
}else{
onInputListener.onInput();
}
}
//定义回调
public interface OnInputListener{
//
void onInputSucess(String code);
//输入状态
void onInput();
}
private OnInputListeneronInputListener;
public void setOnInputListener(OnInputListener onInputListener){
this.onInputListener = onInputListener;
}
/**
* 显示键盘
*/
public void showSoftInput(){
//显示软键盘
if(imm!=null &&et_code!=null) {
et_code.postDelayed(new Runnable() {
@Override
public void run() {
imm.showSoftInput(et_code, 0);
}
},200);
}
}
/**
* 获得手机号验证码
* @return 验证码
*/
public String getPhoneCode(){
StringBuilder sb =new StringBuilder();
for (String code :codes) {
sb.append(code);
}
return sb.toString();
}
}
3.自定义控件的使用
verificationCodeView.setOnInputListener(new VerificationCodeView.OnInputListener() {
@Override
public void onInputInputSucess(String code) {
//输入6个数字后,调用接口查询数据是否正确
}
@Override
public void onInput() {
}
});
verificationCodeView.showSoftInput();
实现非常简单,实现方式比较low