Android利用CountDownTimer实现验证码倒计时效果实例

前言

等待总是让人感到焦急和厌烦的,特别是看不到进展的等待。所以为了不让用户痴痴地等,我们在进行某些耗时操作时,一般都要设计一个进度条或者倒计时器,让进度可视化,告诉用户“等待之后更精彩”。在使用短信验证码注册或者登录App就可以看到这样的设计:点击“发送验证码”的按钮之后,按钮上就会出现倒计时(一般为60秒),倒计时结束之后,按钮的文字就会变成“重新发送”。

在Android中要实现这样的效果可以使用Handler发送消息,但其实还有一个已经封装好的抽象类可以帮上忙,那就是CountDownTimer,利用它,我们可以很轻松地实现倒计时。很久以前我就用过这个类,但是这几天写时发现了一个当初没有注意到的坑,因此打算写一篇博客记录下来。

1、需求分析

  • 点击按钮之后,按钮文字变为“ns后发送验证码”(n为倒计时读数);
  • 为了让倒计时更加醒目,将秒数和单位设为蓝色;
  • 倒计时结束之后,按钮的文字显示为“重新发送”。

瞄一眼效果图:

2、工程创建和布局编写

创建工程就不用多说了,由于我们只需要看到按钮上的倒计时效果,不必输入手机号码,所以只要在界面上简单地放置一个按钮即可:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:padding="16dp"
 tools:context="com.lindroid.countdowndemo.MainActivity">

 <Button
  android:id="@+id/btn_captcha"
  android:layout_width="match_parent"
  android:layout_height="50dp"
  android:background="#c7c7c7"
  android:text="获取验证码"
  android:textAllCaps="false"
  android:textColor="@android:color/black"
  android:textSize="18sp" />

</RelativeLayout>

3、如何使用CountDownTimer

CountDownTimer倒计时器的使用并不难,我们可以创建一个类继承它,并实现它的构造函数和重写两个方法:

 private CountTimer countTimer;

 /**
  * 点击按钮后倒计时
  */
 class CountTimer extends CountDownTimer {

  public CountTimer(long millisInFuture, long countDownInterval) {
   super(millisInFuture, countDownInterval);
  }

  /**
   * 倒计时过程中调用
   *
   * @param millisUntilFinished
   */
  @Override
  public void onTick(long millisUntilFinished) {

  }

  /**
   * 倒计时完成后调用
   */
  @Override
  public void onFinish() {

  }
 }

大体的框架如上所述,我来稍微解释一下。首先是构造函数,里面有两个参数:

  • millisInFuture:倒计时的总时间,单位为毫秒
  • countDownInterval:倒计时的时间间隔,单位为毫秒

比如我想设置10秒的倒计时,每隔1秒就读一次数,那么初始化就可以将数值传入:

CountTimer countTimer = = new CountTimer(10000, 1000);

除了构造函数,还有两个方法,它们的作用分别如下:

  • onTick:倒计时过程中调用
  • onFinish:倒计时结束后调用

那么怎么开启倒计时呢?只需要用countTimer去调用start方法就可以了。另外,为了节省资源,在Activity销毁时应该停止倒计时:

 @Override
 protected void onDestroy() {
  super.onDestroy();
  countTimer.cancel();
 }

到这里,你应该知道怎么使用如何使用CountDownTimer了吧?如果还有疑问,可以在文末下载完整的代码。

4、实现简单的倒计时效果

现在我们先来实现点击按钮后就进行倒计时读数的效果,代码如下:

 CountTimer countTimer = new CountTimer(10000, 1000);

 /**
  * 点击按钮后倒计时
  */
 class CountTimer extends CountDownTimer {

  public CountTimer(long millisInFuture, long countDownInterval) {
   super(millisInFuture, countDownInterval);
  }

  /**
   * 倒计时过程中调用
   *
   * @param millisUntilFinished
   */
  @Override
  public void onTick(long millisUntilFinished) {
   Log.e("Tag", "倒计时=" + (millisUntilFinished/1000));
   btnCaptcha.setText(millisUntilFinished / 1000 + "s后重新发送");
   //设置倒计时中的按钮外观
   btnCaptcha.setClickable(false);//倒计时过程中将按钮设置为不可点击
   btnCaptcha.setBackgroundColor(Color.parseColor("#c7c7c7"));
   btnCaptcha.setTextColor(ContextCompat.getColor(context, android.R.color.black));
   btnCaptcha.setTextSize(16);
  }

  /**
   * 倒计时完成后调用
   */
  @Override
  public void onFinish() {
   Log.e("Tag", "倒计时完成");
   //设置倒计时结束之后的按钮样式
   btnCaptcha.setBackgroundColor(ContextCompat.getColor(context, android.R.color.holo_blue_light));
   btnCaptcha.setTextColor(ContextCompat.getColor(context, android.R.color.white));
   btnCaptcha.setTextSize(18);
   btnCaptcha.setText("重新发送");
   btnCaptcha.setClickable(true);
  }
 }

倒计时的读数是实时的,毫无疑问应该在onTick方法中处理这些逻辑,倒计时完成后要将按钮文字改为“重新发送”,这个可以交给onFinish。

运行一下,点击按钮,倒计时成功出现了,但是再点几次,诡异的事情发生了:有时候倒计时读数会漏掉某个数字,比如从10直接就到8了,打印出来的日志是这样的:

这……到底是怎么回事?少掉的一秒难道是被某人给续了么?

5、CountDownTimer误差解决

为了找回生命中的这一秒钟,我在一个技术群里和小伙伴们讨论了很久,最后算是逃过了时间黑洞的魔爪。

我们采用的倒计时读数是将millisUntilFinished除于1000得到的,这里就有一个小小的陷阱了:millisUntilFinished是长整型变量,除于1000之后得到是整数部分。我们可以将millisUntilFinished的值打印出来看看:

现在明白为什么看不到读数9了吗?那是因为程序执行虽然很快,但再快也是需要时间的,所以从10秒倒计时到9秒时,millisUntilFinished会比9000稍小一点,是8999,而长整型8999除于1000之后就得到8了。当然,既然是误差那就有多种情况,少掉的数字不一定是9,这里只是我针对我遇到的情况而言。

知道原因之后就好办了,我们可以先将millisUntilFinished转换成double类型后再除于1000,这样就可以保留小数部分了,然后使用Math类中的round方法四舍五入,但是这样倒计时的话会从10到2,这显然不行,所以再减去1,让它从9到1。修改后的onTick方法代码是这样的:

  public void onTick(long millisUntilFinished) {
   //处理后的倒计时数值
   int time = (int) (Math.round((double) millisUntilFinished / 1000) - 1);
   btnCaptcha.setText(String.valueOf(time)+"s后重新发送");
   //设置倒计时中的按钮外观
   btnCaptcha.setClickable(false);//倒计时过程中将按钮设置为不可点击
   btnCaptcha.setBackgroundColor(Color.parseColor("#c7c7c7"));
   btnCaptcha.setTextColor(ContextCompat.getColor(context, android.R.color.black));
   btnCaptcha.setTextSize(16);
  }

运行后试试,就可以发现失去的那一秒又回来啦。

6、给倒计时读数和单位设置前景色

给同一字符串中的不同字符设置不同的字体颜色,这就需要用到SpannableString与SpannableStringBuilder相关的知识了,限于篇幅,这里就不赘述了,可以参考这篇文章:SpannableString与SpannableStringBuilder。这里只简单介绍一下:

6.1 拼接字符串

   int time = (int) (Math.round((double) millisUntilFinished / 1000) - 1);
   //拼接要显示的字符串
   SpannableStringBuilder sb = new SpannableStringBuilder();
   sb.append(String.valueOf(time));
   sb.append("s后重新发送");

6.2 设置要显示的文字样式

   //字符“后”在字符串中的下标
   int index = String.valueOf(sb).indexOf("后");
   //给秒数和单位设置蓝色前景色
   ForegroundColorSpan colorSpan = new ForegroundColorSpan(ContextCompat.getColor(context, android.R.color.holo_blue_dark));
   sb.setSpan(colorSpan, 0, index, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
   btnCaptcha.setText(sb);

这次运行之后就可以看到跟效果图一样的效果了。最后给一下源码:CountDownTimerDemo

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • Android使用CountDownTimer实现倒数定时器效果

    实现倒计时的效果 例子:发送验证码按钮 效果图: /** * 倒计时 * * @author admin * */ public class MainActivity extends ActionBarActivity { private Button tvTime;// 显示时间 private MyCountDownTimer myCountDownTimer;// 倒计时对象 @Override protected void onCreate(Bundle savedInstanceSta

  • Android基于CountDownTimer实现倒计时功能

    本文实例讲述了Android编程基于CountDownTimer实现倒计时功能的方法.分享给大家供大家参考,具体如下: 在逛论坛的时候,看到一个网友提问,说到了CountDownTimer这个类,从名字上面大家就可以看出来,记录下载时间.将后台线程的创建和Handler队列封装成一个方便的类调用. 查看了一下官方文档,这个类及其简单,只有四个方法,上面都涉及到了onTick,onFinsh.cancel和start.其中前面两个是抽象方法,所以要重写一下. 下面是官方给的一个小例子: new C

  • Android 列表倒计时的实现的示例代码(CountDownTimer)

    实习一段时间了,一直想写点技术总结,但一直没找到合适的主题.刚好,最近版本中我负责的模块遇到了个线程相关问题(之前一直画界面,做点基础功能,有点乏味),列表项倒计时的实现. 于是乎,我的第一篇android技术文章就诞生了. [醒目]该demo用Kotlin语言实现. 背景介绍 需要在ListView的item里实现倒计时,初看还挺简单的,但是真正做的时候也遇到了不少坑. 网上有不少类似文章,有用对TextView扩展实现的,也有用自带的CountDownTimer实现的,本文就是用CountD

  • Android中CountDownTimer 实现倒计时功能

    CountDownTimer CountDownTimer 是android 自带的一个倒计时类,使用这个类可以很简单的实现 倒计时功能 CountDownTimer 的实现方式 new CountDownTimer(6000,1000) {//第一个参数表示的是倒计时的总时间,第二参数表示的是倒计时的间隔时间. @Override public void onTick(long millisUntilFinished) {//倒计时的过程 textView.setText(millisUnti

  • Android利用CountDownTimer实现点击获取验证码倒计时效果

    本文实例为大家分享了Android点击获取验证码倒计时的具体代码,供大家参考,具体内容如下 package com.loaderman.countdowntimerdemo; import android.os.Bundle; import android.os.CountDownTimer; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextV

  • Android中CountDownTimer倒计时器用法实例

    本文实例讲述了Android中CountDownTimer倒计时器用法.分享给大家供大家参考,具体如下: 在平时我们编程的时候,经常会用到倒计时这个功能,很多人不知道Android已经帮封装好了一个类,往往都自己写.现在发现了这个类,大家共享一下: 在一个TextView不断显示剩下的时间,代码如下: private TextView vertifyView; private CountDownTimer timer = new CountDownTimer(10000, 1000) { @Ov

  • Android中使用Handler及Countdowntimer实现包含倒计时的闪屏页面

    上一篇博文<Android中Handler使用浅析>通过实现倒计时闪屏页面的制作引出了Handler的使用方法以及实现原理,博文末尾也提到了实现过程中的Bug,有兴趣的朋友可以点击链接回去看看.今天通过使用Handler以及CountDownTimer来实现完整版的倒计时闪屏(不会出现在退出闪屏页后,依然会跳转页面的现象). 1. 实现效果如下: 1.1  正常进入跳转的效果以及log显示 1.2  倒计时未结束时退出以及log显示 对比上篇博文的实现,退出后计时停止且不会再跳到新的界面 2.

  • Android CountDownTimer实现倒计时器

    使用介绍 开发中经常会遇到一些和倒计时有关的场景,比如发送验证码的按钮,会在点击发送后,显示倒计时间,倒计时结束后才能够刷新按钮,再次允许点击.为了不阻塞软件的运行,又要实时刷新界面,我们通常会用到 Handler 或者 AsyncTask 等技术,自己写逻辑实现.其实 Android 中已经封装好了一套 CountDownTimer 来实现这个功能需求. CountDownTimer(long millisInFuture, long countDownInterval) CountDownT

  • Android利用CountDownTimer实现倒计时功能 Android实现停留5s跳转到登录页面

    利用CountDownTimer实现倒计时,停留5s跳转到登录页面功能,具体如下 举个栗子,引导页面最后一个界面要停留5s跳转到登录页面.代码如下: //假设 这是引导页面最后一个界面 public class MainActivity extends Activity { private TextView count_time; private MyCountDownTimer myCountDownTimer; @Override protected void onCreate(Bundle

  • Android使用CountDownTimer实现倒计时效果

    在开发中会经常用到倒计时这个功能,包括给手机发送验证码等等,之前我的做法都是使用Handler + Timer + TimerTask来实现,现在发现了这个类,果断抛弃之前的做法,相信还是有很多人和我一样一开始不知道Android已经帮我们封装好了一个叫CountDownTimer的类. 从字面上就可以看出来它叫倒数计时器又称定时器或计时器,采用Handler的方式实现,将后台线程的创建和Handler队列封装而成. 看了一下源码,发现这个类的调用还蛮简单,只有四个方法: (1)public a

随机推荐