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
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
推荐阅读
-
Android利用CountDownTimer实现验证码倒计时效果实例
-
Android利用CountDownTimer实现点击获取验证码倒计时效果
-
Android利用CountDownTimer实现验证码倒计时效果实例
-
Android利用CountDownTimer实现倒计时功能 Android实现停留5s跳转到登录页面
-
Android利用RecyclerView实现列表倒计时效果
-
Android利用CountDownTimer实现倒计时功能 Android实现停留5s跳转到登录页面
-
Android实现自定义验证码输入框效果(实例代码)
-
Android如何利用RecyclerView实现列表倒计时效果实例代码
-
android 利用CountDownTimer实现验证码倒计时效果
-
Android利用RecyclerView实现列表倒计时效果