最近自己自定义了一个倒计时按钮,类似于获取验证码的倒计时按钮的效果。实现基于CountDownTimer。
直接贴上代码:
utils类:
public class TimerUtil extends CountDownTimer {
private CountDownTimerListener mCountDownTimerListener;
public TimerUtil(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onTick(long millisUntilFinished) {
if (mCountDownTimerListener != null) {
mCountDownTimerListener.startCount(millisUntilFinished);
}
}
@Override
public void onFinish() {
if (mCountDownTimerListener != null) {
mCountDownTimerListener.finishCount();
}
}
public void setCountDownTimerListener(CountDownTimerListener listener) {
mCountDownTimerListener = listener;
}
public interface CountDownTimerListener {
void startCount(long millsUtilFinished);
void finishCount();
}
}
修改CountDownTimer
倒计时显示到一秒的时候,会出现短暂延时,查看源码我们可以发现,在一秒更新UI后,就不会再更新UI了,所以,我们需要修改相应的代码。主要是删除了对应的一段判断。如下:
public abstract class CountDownTimer {
/**
* Millis since epoch when alarm should stop.
*/
private final long mMillisInFuture;
/**
* The interval in millis that the user receives callbacks
*/
private final long mCountdownInterval;
private long mStopTimeInFuture;
/**
* boolean representing if the timer was cancelled
*/
private boolean mCancelled = false;
/**
* @param millisInFuture The number of millis in the future from the call
* to {@link #start()} until the countdown is done and {@link #onFinish()}
* is called.
* @param countDownInterval The interval along the way to receive
* {@link #onTick(long)} callbacks.
*/
public CountDownTimer(long millisInFuture, long countDownInterval) {
mMillisInFuture = millisInFuture-1;
mCountdownInterval = countDownInterval;
}
/**
* Cancel the countdown.
*/
public synchronized final void cancel() {
mCancelled = true;
mHandler.removeMessages(MSG);
}
/**
* Start the countdown.
*/
public synchronized final CountDownTimer start() {
mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
}
mStopTimeInFuture = SystemClock.elapsedRealtime() + mMillisInFuture;
mHandler.sendMessage(mHandler.obtainMessage(MSG));
return this;
}
/**
* Callback fired on regular interval.
* @param millisUntilFinished The amount of time until finished.
*/
public abstract void onTick(long millisUntilFinished);
/**
* Callback fired when the time is up.
*/
public abstract void onFinish();
private static final int MSG = 1;
// handles counting down
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {
if (mCancelled) {
return;
}
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
onFinish(); //删除了这里的一段判断
} else {
long lastTickStart = SystemClock.elapsedRealtime();
onTick(millisLeft);
// take into account user's onTick taking time to execute
long delay = lastTickStart + mCountdownInterval - SystemClock.elapsedRealtime();
// special case: user's onTick took more than interval to
// complete, skip to next interval
while (delay < 0) delay += mCountdownInterval;
sendMessageDelayed(obtainMessage(MSG), delay);
}
}
}
};
}
倒计时按钮的代码具体实现:
public class CountDownTimerButton extends android.support.v7.widget.AppCompatButton {
private final String TAG = CountDownTimerButton.class.getSimpleName();
private final int STATE_STARTCOUNT = 0;
private final int STATE_STOPCOUNT = 1;
private String startCountDownStateColor;
private String stopCountDownStateColor;
private String startCountDownText;
private String stopCountDownText;
private TimerUtil mTimerUtil;
private CountDownStateChangeListener mCountDownStateChangeListener;
public interface CountDownStateChangeListener{
void onStartCount(long millsUtilFinished);
void onFinishCount();
}
public CountDownTimerButton(Context context) {
this(context, null);
}
public CountDownTimerButton(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.buttonStyle);
}
public CountDownTimerButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void onDestroy() {
Log.d(TAG, "run in onDestroy,currentTimeMillis: " + System.currentTimeMillis());
if (mTimerUtil != null) {
mTimerUtil.cancel();
mTimerUtil = null;
}
initState();
}
private void initState() {
changeBackGroundColor(STATE_STOPCOUNT);
setClickable(true);
setText(stopCountDownText);
}
public void setCountDownStateChangeListener(CountDownStateChangeListener listener){
mCountDownStateChangeListener=listener;
}
public void setStartCountDownStateColor(String color) {
startCountDownStateColor = color;
}
public void setStopCountDownColor(String color) {
stopCountDownStateColor = color;
}
public void setStartCountDownText(String startCountDownText) {
this.startCountDownText = startCountDownText;
}
private void setStopCountDownText(String stopCountDownText) {
this.stopCountDownText = stopCountDownText;
}
public void startCountDownTimer(final long millisInFuture, final long countDownInterval) {
if (mTimerUtil != null) {
mTimerUtil.cancel();
mTimerUtil = null;
}
setStopCountDownText(getText().toString());
mTimerUtil = new TimerUtil(millisInFuture, countDownInterval);
mTimerUtil.setCountDownTimerListener(new TimerUtil.CountDownTimerListener() {
@Override
public void startCount(long millsUtilFinished) {
if (mCountDownStateChangeListener!=null){
mCountDownStateChangeListener.onStartCount(millsUtilFinished);
return;
}
changeBackGroundColor(STATE_STARTCOUNT);
setClickable(false);
setText(startCountDownText+"(" + millsUtilFinished / 1000 + ")");
}
@Override
public void finishCount() {
if (mCountDownStateChangeListener!=null){
mCountDownStateChangeListener.onFinishCount();
return;
}
setText(stopCountDownText);
setClickable(true);
changeBackGroundColor(STATE_STOPCOUNT);
}
});
mTimerUtil.start();
}
private void changeBackGroundColor(int state) {
try {
GradientDrawable drawable = (GradientDrawable) getBackground();
switch (state) {
case STATE_STARTCOUNT:
if (TextUtils.isEmpty(startCountDownStateColor)) {
drawable.setColor(Color.parseColor("#d3d2d6"));
} else {
drawable.setColor(Color.parseColor(startCountDownStateColor));
}
break;
case STATE_STOPCOUNT:
if (TextUtils.isEmpty(stopCountDownStateColor)) {
drawable.setColor(Color.parseColor("#ffffff"));
} else {
drawable.setColor(Color.parseColor(stopCountDownStateColor));
}
break;
default:
break;
}
} catch (ClassCastException e) {
e.fillInStackTrace();
}
}
具体使用:
get_ver_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
get_ver_btn.startCountDownTimer(10000,1000);
get_ver_btn.setStartCountDownText("再次获取");
}
});