自定义发送验证码按钮(没有实现发送验证码业务 只有UI效果)
大家都知道在一个项目的开发中,发送短信验证码是必不可少的业务,接下来给大家讲的就是如何自定义发送短信验证码的按钮。
第一步:新建一个java类:GetCode.java
package com.wj.imchatclient.commonmodle.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.EditText;
import android.widget.TextView;
import com.wj.imchatclient.R;
import com.wj.imchatclient.commonmodle.utils.L;
import com.wj.imchatclient.commonmodle.utils.T;
import com.wj.imchatclient.commonmodle.utils.ValueUtils;
/**
* 发送验证码的按钮
* Created by WJ on 2016/7/31.
*/
public class GetCode extends TextView {
private final String TAG = "GetCode";//标签
private final int UPDATE_TEXT = 1;//更新文本内容的what
private final int UPDATE_STATUS = 2;//更新状态
private boolean canClick = false;//是否可以点击
private int delay_time = 10;//一次倒计时的总数s
private int time = delay_time;//正在倒计时的s
private OnGetCodeListener onGetCodeListener;
public void setOnGetCodeListener(OnGetCodeListener onGetCodeListener) {
this.onGetCodeListener = onGetCodeListener;
}
public interface OnGetCodeListener {
EditText getInput();
boolean getPhone();
void getCode();
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == UPDATE_TEXT) {
//更新内容
setText(ValueUtils.getString(R.string.get_code) + "(" + time + ")");
} else if (msg.what == UPDATE_STATUS) {
//更新状态
setEnabled(canClick);
setText(ValueUtils.getString(R.string.get_code));
}
}
};
public GetCode(Context context) {
super(context);
}
public GetCode(Context context, AttributeSet attrs) {
super(context, attrs);
initData(context, attrs);
}
public GetCode(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initData(context, attrs);
}
public GetCode(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initData(context, attrs);
}
public void initData(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.GetCode);
delay_time = typedArray.getInteger(R.styleable.GetCode_delay_time, delay_time);
time = delay_time;
L.e(TAG, "正在加载属性=" + delay_time);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
L.e(TAG, "onTouchEvent==" + event.getAction());
if (event.getAction() == MotionEvent.ACTION_UP) {
//按下去了
if (onGetCodeListener != null) {
boolean isPhone = onGetCodeListener.getPhone();//发送验证码
L.e(TAG, "是不是手机号呢?" + isPhone);
if (isPhone) {
//是手机号
canClick = true;
} else {
canClick = false;
//设置input的焦点
onGetCodeListener.getInput().setFocusable(true);
onGetCodeListener.getInput().setFocusableInTouchMode(true);
onGetCodeListener.getInput().requestFocus();
onGetCodeListener.getInput().requestFocusFromTouch();
}
}
if (canClick) {
canClick = false;
setEnabled(canClick);
startTimeThread();//启动倒计时
if (onGetCodeListener != null) {
onGetCodeListener.getCode();
}
} else {
T.show(getContext(), "请输入正确的手机号");
}
L.e(TAG, "canClick==" + canClick);
}
return super.onTouchEvent(event);
}
@Override
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
L.e(TAG, "onWindowVisibilityChanged==" + visibility + "===" + (visibility == GONE));
if (visibility == GONE) {
//内容没了 停止线程减少不必要的资源
canClick = true;
setEnabled(canClick);
}
}
/**
* 倒计时线程
*/
private void startTimeThread() {
new Thread(new Runnable() {
@Override
public void run() {
while (canClick == false) {
time--;
L.e(TAG, Thread.currentThread().getName() + "线程还在运行中======" + time);
if (time == 0) {
time = delay_time;
canClick = true;
handler.sendEmptyMessage(UPDATE_STATUS);
} else {
handler.sendEmptyMessage(UPDATE_TEXT);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
第二步:注意在以上的自定义View中使用了自定义的属性,所以需要在res/values/atts.xml中添加以下内容:
<declare-styleable name="GetCode">
<attr name="delay_time" format="integer"/>
</declare-styleable>
添加这个的作用是可以在布局中自定义倒计时的时间(单位:s)
第三步:在布局xml中使用GetCode自定义View(注意:笔者在这没有使用Button,而是使用了TextView 所以需要设置宽高来改变TextView的外观 具体为什么不用Button就是笔者习惯使用TextView了。)
<com.wj.imchatclient.commonmodle.view.GetCode
android:id="@+id/v_getcode"
android:layout_width="@dimen/dp100"
android:layout_height="@dimen/dp30"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/dp5"
android:layout_marginRight="@dimen/dp5"
android:background="@drawable/bg_get_code"
android:clickable="true"
android:gravity="center"
android:text="@string/get_code"
android:textColor="@android:color/white"
app:delay_time="60"
/>
以上属性笔者只讲一下
app:delay_time="60"
android:background="@drawable/bg_get_code"
app:delay_time:就是刚刚说的自定义属性了 60表示倒计时长为60s
android:background:这里引用了drawable对象选择器,需要在res/drawable下新建一个xml命名为:bg_get_code
1新建 .bg_get_code.xml 代码如下: 选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:drawable="@drawable/bg_get_code_false"/>
<item android:state_enabled="true" android:drawable="@drawable/bg_get_code_true"/>
</selector>
2.新建 bg_get_code_true.xml:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp5"/>
<solid android:color="@color/colorAccent"/>
</shape>
3.新建 bg_get_code_false.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="@dimen/dp5" />
<solid android:color="@color/c_9B9DB1" />
</shape>
第四步:在Activity中获取GetCode实例 设置监听
GetCode getCode= (GetCode) findViewById(R.id.v_getcode);
getCode.setOnGetCodeListener(this);
@Override
public EditText getInput() {
return etMobile;
}
@Override
public boolean getPhone() {
return RegularUtils.phone(etMobile.getText().toString());
}
@Override
public void getCode() {
//发送验证码
T.show(this, "正在发送验证码到-" + etMobile.getText().toString());
}
getInput:返回输入框的实例EditText。
getPhone:作用是返回一个是不是手机号的boolean值,true是手机号 会调用getCode方法去实现发送验证码业务,false不是手机号 不会调用getCode方法。
getCode:实现发送验证码业务。