在我们的应用中,有些地方需要我们输入验证码的操作,并且带有倒计时功能,比如说忘记密码,修改手机号码,激活等等,整好我的项目中也用到了,就贴出来供大家参考。
实现原理很简单就是在布局中同时添加TextView和Editext,并且他们是重叠在一起的,我么通过Editext的监听来将获取到的内容放到Text里面。
倒计时功能: 自定义控件继承CountDownTimer类,实现它的onTick和onFinish方法,具体讲解在代码中。
package jx.com.verificationcode;
import android.content.Context;
import android.os.CountDownTimer;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.widget.TextView;
/**
* Created by zsd on 2016/6/27.
* 倒计时
*/
public class CountDownTimerUtils extends CountDownTimer {
private TextView mTextView;
private Context mContext;
public CountDownTimerUtils(TextView textView, long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
this.mTextView = textView;
}
@Override
public void onTick(long millisUntilFinished) {
mTextView.setClickable(false); //设置不可点击
mTextView.setText("重新获取验证码" + millisUntilFinished / 1000 + "s"); //设置倒计时时间
mTextView.setTextSize(14);
// mTextView.setBackgroundResource(R.drawable.bg_identify_code_press); //设置按钮为灰色,这时是不能点击的
/**
* 超链接 URLSpan
* 文字背景颜色 BackgroundColorSpan
* 文字颜色 ForegroundColorSpan
* 字体大小 AbsoluteSizeSpan
* 粗体、斜体 StyleSpan
* 删除线 StrikethroughSpan
* 下划线 UnderlineSpan
* 图片 ImageSpan
* http://blog.youkuaiyun.com/ah200614435/article/details/7914459
*/
SpannableString spannableString = new SpannableString(mTextView.getText().toString()); //获取按钮上的文字
ForegroundColorSpan span = new ForegroundColorSpan(BaseApplication.getAppContext().getResources().getColor(R.color.colorBlue));
/**
* public void setSpan(Object what, int start, int end, int flags) {
* 主要是start跟end,start是起始位置,无论中英文,都算一个。
* 从0开始计算起。end是结束位置,所以处理的文字,包含开始位置,但不包含结束位置。
*/
spannableString.setSpan(span, 7, mTextView.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//将倒计时的时间设置为蓝色
mTextView.setText(spannableString);
}
@Override
public void onFinish() {
mTextView.setText("重新获取验证码");
mTextView.setClickable(true);//重新获得点击
// mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal); //还原背景色
}
}
简易实现逻辑:
输入手机号码或者邮箱,从后台获取验证码,手机号码输入及邮箱输入就不写了,跳转到到验证页面,,然后将手机或邮箱的验证码填入到验证码输入框进行验证
验证码CheckCodeView实现代码
package jx.com.verificationcode;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
/**
* Created by zsd on 16/6/27.
*/
public class CheckCodeView extends RelativeLayout {
private EditText editText;
private TextView[] TextViews; //用于存放输入的数字
private StringBuffer stringBuffer = new StringBuffer();
private int count = 4; //输入的个数,这个可以自己根据需求来定义
private String inputContent; //输入内容
public CheckCodeView(Context context) {
this(context, null);
}
public CheckCodeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CheckCodeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TextViews = new TextView[4];
View.inflate(context, R.layout.view_check_code, this);
editText = (EditText) findViewById(R.id.item_edittext);
TextViews[0] = (TextView) findViewById(R.id.item_code_iv1);
TextViews[1] = (TextView) findViewById(R.id.item_code_iv2);
TextViews[2] = (TextView) findViewById(R.id.item_code_iv3);
TextViews[3] = (TextView) findViewById(R.id.item_code_iv4);
editText.setCursorVisible(false);//将光标隐藏
//editext的监听
editText.addTextChangedListener(mEditextWatchListener);
editText.setOnKeyListener(mOnkeyListener);
}
TextWatcher mEditextWatchListener = 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.toString().equals("")) {
if (stringBuffer.length() > 3) {
//当文本长度大于3位时edittext置空
editText.setText("");
return;
} else {
//将文字添加到StringBuffer中
stringBuffer.append(editable);
editText.setText("");//添加后将EditText置空
// Log.e("TAG", "afterTextChanged: stringBuffer is " + stringBuffer);
count = stringBuffer.length();//记录stringbuffer的长度
inputContent = stringBuffer.toString();
if (stringBuffer.length() == 4) {
//文字长度位4 则调用完成输入的监听
if (inputCompleteListener != null) {
inputCompleteListener.inputComplete();
}
}
}
for (int i = 0; i < stringBuffer.length(); i++) {
TextViews[i].setText(String.valueOf(inputContent.charAt(i)));
TextViews[i].setBackgroundResource(R.mipmap.bg_verify_press);
}
}
}
};
OnKeyListener mOnkeyListener = new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL&& event.getAction() == KeyEvent.ACTION_DOWN) {
if (onKeyDelete()) return true;
return true;
}
return false;
}
};
public boolean onKeyDelete() {
if (count == 0) {
count = 4;
return true;
}
if (stringBuffer.length() > 0) {
//删除相应位置的字符
stringBuffer.delete((count - 1), count);
count--;
inputContent = stringBuffer.toString();
TextViews[stringBuffer.length()].setText("");
TextViews[stringBuffer.length()].setBackgroundResource(R.mipmap.bg_verify);
if (inputCompleteListener != null)
inputCompleteListener.deleteContent(true);//有删除就通知manger
}
return false;
}
/**
* 清空输入内容
*/
public void clearEditText() {
stringBuffer.delete(0, stringBuffer.length());
inputContent = stringBuffer.toString();
for (int i = 0; i < TextViews.length; i++) {
TextViews[i].setText("");
TextViews[i].setBackgroundResource(R.mipmap.bg_verify);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return super.onKeyDown(keyCode, event);
}
private InputCompleteListener inputCompleteListener;
public void setInputCompleteListener(InputCompleteListener inputCompleteListener) {
this.inputCompleteListener = inputCompleteListener;
}
public interface InputCompleteListener {
void inputComplete();
void deleteContent(boolean isDelete);
}
/**
* 获取输入文本
*
* @return
*/
public String getEditContent() {
return inputContent;
}
}
view_check_code.xml布局:
<?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="wrap_content"
android:layout_height="47dp"
android:gravity="center"
android:orientation="horizontal"
android:weightSum="3">
<TextView
android:id="@+id/item_code_iv1"
style="@style/edit_style" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/item_code_iv2"
style="@style/edit_style" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/item_code_iv3"
style="@style/edit_style" />
<View
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/item_code_iv4"
style="@style/edit_style" />
</LinearLayout>
<EditText
android:id="@+id/item_edittext"
android:layout_width="match_parent"
android:layout_height="46dp"
android:background="@android:color/transparent"
android:inputType="number" />
</RelativeLayout>
edit_style:
<style name="edit_style" >
<item name="android:layout_height">47dp</item>
<item name="android:layout_width">47dp</item>
<item name="android:background">@mipmap/bg_verify</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@color/common_blue_0090FF</item>
<item name="android:textSize">18sp</item>
</style>
验证码验证页面,需要验证验证码正确与否可以自行添加逻辑:
package jx.com.verificationcode;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by zsd on 2016/6/27
* desc:
*/
public class SecondActivity extends AppCompatActivity implements CheckCodeView.InputCompleteListener {
private CheckCodeView checkCodeView;
private TextView text;
private CountDownTimerUtils mCountDownTimerUtils;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
initView();
checkCodeView.setInputCompleteListener(this);
mCountDownTimerUtils = new CountDownTimerUtils(text, 60000, 1000);
mCountDownTimerUtils.start();
}
private void initView() {
checkCodeView = (CheckCodeView) findViewById(R.id.check_code_view);
text = (TextView) findViewById(R.id.tv_text);
}
@Override
public void inputComplete() {
Toast.makeText(getApplicationContext(), "验证码是:" + checkCodeView.getEditContent(), Toast.LENGTH_LONG).show();
}
@Override
public void deleteContent(boolean isDelete) {
if (isDelete){
text.setText("重新获取验证码");
mCountDownTimerUtils.start();
}
}
}
activity_second.xml
<?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="match_parent"
>
<jx.com.verificationcode.CheckCodeView
android:id="@+id/check_code_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="20dp" />
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/check_code_view"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="40dp"
android:textSize="16dp"
android:text="重新获取验证码" />
</RelativeLayout>