Android利用CountDownTimer實(shí)現(xiàn)驗(yàn)證碼倒計(jì)時(shí)效果實(shí)例
前言
等待總是讓人感到焦急和厭煩的,特別是看不到進(jìn)展的等待。所以為了不讓用戶癡癡地等,我們?cè)谶M(jìn)行某些耗時(shí)操作時(shí),一般都要設(shè)計(jì)一個(gè)進(jìn)度條或者倒計(jì)時(shí)器,讓進(jìn)度可視化,告訴用戶“等待之后更精彩”。在使用短信驗(yàn)證碼注冊(cè)或者登錄App就可以看到這樣的設(shè)計(jì):點(diǎn)擊“發(fā)送驗(yàn)證碼”的按鈕之后,按鈕上就會(huì)出現(xiàn)倒計(jì)時(shí)(一般為60秒),倒計(jì)時(shí)結(jié)束之后,按鈕的文字就會(huì)變成“重新發(fā)送”。
在Android中要實(shí)現(xiàn)這樣的效果可以使用Handler發(fā)送消息,但其實(shí)還有一個(gè)已經(jīng)封裝好的抽象類可以幫上忙,那就是CountDownTimer,利用它,我們可以很輕松地實(shí)現(xiàn)倒計(jì)時(shí)。很久以前我就用過(guò)這個(gè)類,但是這幾天寫時(shí)發(fā)現(xiàn)了一個(gè)當(dāng)初沒(méi)有注意到的坑,因此打算寫一篇博客記錄下來(lái)。
1、需求分析
- 點(diǎn)擊按鈕之后,按鈕文字變?yōu)椤皀s后發(fā)送驗(yàn)證碼”(n為倒計(jì)時(shí)讀數(shù));
- 為了讓倒計(jì)時(shí)更加醒目,將秒數(shù)和單位設(shè)為藍(lán)色;
- 倒計(jì)時(shí)結(jié)束之后,按鈕的文字顯示為“重新發(fā)送”。
瞄一眼效果圖:
2、工程創(chuàng)建和布局編寫
創(chuàng)建工程就不用多說(shuō)了,由于我們只需要看到按鈕上的倒計(jì)時(shí)效果,不必輸入手機(jī)號(hào)碼,所以只要在界面上簡(jiǎn)單地放置一個(gè)按鈕即可:
<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="獲取驗(yàn)證碼" android:textAllCaps="false" android:textColor="@android:color/black" android:textSize="18sp" /> </RelativeLayout>
3、如何使用CountDownTimer
CountDownTimer倒計(jì)時(shí)器的使用并不難,我們可以創(chuàng)建一個(gè)類繼承它,并實(shí)現(xiàn)它的構(gòu)造函數(shù)和重寫兩個(gè)方法:
private CountTimer countTimer; /** * 點(diǎn)擊按鈕后倒計(jì)時(shí) */ class CountTimer extends CountDownTimer { public CountTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } /** * 倒計(jì)時(shí)過(guò)程中調(diào)用 * * @param millisUntilFinished */ @Override public void onTick(long millisUntilFinished) { } /** * 倒計(jì)時(shí)完成后調(diào)用 */ @Override public void onFinish() { } }
大體的框架如上所述,我來(lái)稍微解釋一下。首先是構(gòu)造函數(shù),里面有兩個(gè)參數(shù):
- millisInFuture:倒計(jì)時(shí)的總時(shí)間,單位為毫秒
- countDownInterval:倒計(jì)時(shí)的時(shí)間間隔,單位為毫秒
比如我想設(shè)置10秒的倒計(jì)時(shí),每隔1秒就讀一次數(shù),那么初始化就可以將數(shù)值傳入:
CountTimer countTimer = = new CountTimer(10000, 1000);
除了構(gòu)造函數(shù),還有兩個(gè)方法,它們的作用分別如下:
- onTick:倒計(jì)時(shí)過(guò)程中調(diào)用
- onFinish:倒計(jì)時(shí)結(jié)束后調(diào)用
那么怎么開啟倒計(jì)時(shí)呢?只需要用countTimer去調(diào)用start方法就可以了。另外,為了節(jié)省資源,在Activity銷毀時(shí)應(yīng)該停止倒計(jì)時(shí):
@Override protected void onDestroy() { super.onDestroy(); countTimer.cancel(); }
到這里,你應(yīng)該知道怎么使用如何使用CountDownTimer了吧?如果還有疑問(wèn),可以在文末下載完整的代碼。
4、實(shí)現(xiàn)簡(jiǎn)單的倒計(jì)時(shí)效果
現(xiàn)在我們先來(lái)實(shí)現(xiàn)點(diǎn)擊按鈕后就進(jìn)行倒計(jì)時(shí)讀數(shù)的效果,代碼如下:
CountTimer countTimer = new CountTimer(10000, 1000); /** * 點(diǎn)擊按鈕后倒計(jì)時(shí) */ class CountTimer extends CountDownTimer { public CountTimer(long millisInFuture, long countDownInterval) { super(millisInFuture, countDownInterval); } /** * 倒計(jì)時(shí)過(guò)程中調(diào)用 * * @param millisUntilFinished */ @Override public void onTick(long millisUntilFinished) { Log.e("Tag", "倒計(jì)時(shí)=" + (millisUntilFinished/1000)); btnCaptcha.setText(millisUntilFinished / 1000 + "s后重新發(fā)送"); //設(shè)置倒計(jì)時(shí)中的按鈕外觀 btnCaptcha.setClickable(false);//倒計(jì)時(shí)過(guò)程中將按鈕設(shè)置為不可點(diǎn)擊 btnCaptcha.setBackgroundColor(Color.parseColor("#c7c7c7")); btnCaptcha.setTextColor(ContextCompat.getColor(context, android.R.color.black)); btnCaptcha.setTextSize(16); } /** * 倒計(jì)時(shí)完成后調(diào)用 */ @Override public void onFinish() { Log.e("Tag", "倒計(jì)時(shí)完成"); //設(shè)置倒計(jì)時(shí)結(jié)束之后的按鈕樣式 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("重新發(fā)送"); btnCaptcha.setClickable(true); } }
倒計(jì)時(shí)的讀數(shù)是實(shí)時(shí)的,毫無(wú)疑問(wèn)應(yīng)該在onTick方法中處理這些邏輯,倒計(jì)時(shí)完成后要將按鈕文字改為“重新發(fā)送”,這個(gè)可以交給onFinish。
運(yùn)行一下,點(diǎn)擊按鈕,倒計(jì)時(shí)成功出現(xiàn)了,但是再點(diǎn)幾次,詭異的事情發(fā)生了:有時(shí)候倒計(jì)時(shí)讀數(shù)會(huì)漏掉某個(gè)數(shù)字,比如從10直接就到8了,打印出來(lái)的日志是這樣的:
這……到底是怎么回事?少掉的一秒難道是被某人給續(xù)了么?
5、CountDownTimer誤差解決
為了找回生命中的這一秒鐘,我在一個(gè)技術(shù)群里和小伙伴們討論了很久,最后算是逃過(guò)了時(shí)間黑洞的魔爪。
我們采用的倒計(jì)時(shí)讀數(shù)是將millisUntilFinished除于1000得到的,這里就有一個(gè)小小的陷阱了:millisUntilFinished是長(zhǎng)整型變量,除于1000之后得到是整數(shù)部分。我們可以將millisUntilFinished的值打印出來(lái)看看:
現(xiàn)在明白為什么看不到讀數(shù)9了嗎?那是因?yàn)槌绦驁?zhí)行雖然很快,但再快也是需要時(shí)間的,所以從10秒倒計(jì)時(shí)到9秒時(shí),millisUntilFinished會(huì)比9000稍小一點(diǎn),是8999,而長(zhǎng)整型8999除于1000之后就得到8了。當(dāng)然,既然是誤差那就有多種情況,少掉的數(shù)字不一定是9,這里只是我針對(duì)我遇到的情況而言。
知道原因之后就好辦了,我們可以先將millisUntilFinished轉(zhuǎn)換成double類型后再除于1000,這樣就可以保留小數(shù)部分了,然后使用Math類中的round方法四舍五入,但是這樣倒計(jì)時(shí)的話會(huì)從10到2,這顯然不行,所以再減去1,讓它從9到1。修改后的onTick方法代碼是這樣的:
public void onTick(long millisUntilFinished) { //處理后的倒計(jì)時(shí)數(shù)值 int time = (int) (Math.round((double) millisUntilFinished / 1000) - 1); btnCaptcha.setText(String.valueOf(time)+"s后重新發(fā)送"); //設(shè)置倒計(jì)時(shí)中的按鈕外觀 btnCaptcha.setClickable(false);//倒計(jì)時(shí)過(guò)程中將按鈕設(shè)置為不可點(diǎn)擊 btnCaptcha.setBackgroundColor(Color.parseColor("#c7c7c7")); btnCaptcha.setTextColor(ContextCompat.getColor(context, android.R.color.black)); btnCaptcha.setTextSize(16); }
運(yùn)行后試試,就可以發(fā)現(xiàn)失去的那一秒又回來(lái)啦。
6、給倒計(jì)時(shí)讀數(shù)和單位設(shè)置前景色
給同一字符串中的不同字符設(shè)置不同的字體顏色,這就需要用到SpannableString與SpannableStringBuilder相關(guān)的知識(shí)了,限于篇幅,這里就不贅述了,可以參考這篇文章:SpannableString與SpannableStringBuilder。這里只簡(jiǎn)單介紹一下:
6.1 拼接字符串
int time = (int) (Math.round((double) millisUntilFinished / 1000) - 1); //拼接要顯示的字符串 SpannableStringBuilder sb = new SpannableStringBuilder(); sb.append(String.valueOf(time)); sb.append("s后重新發(fā)送");
6.2 設(shè)置要顯示的文字樣式
//字符“后”在字符串中的下標(biāo) int index = String.valueOf(sb).indexOf("后"); //給秒數(shù)和單位設(shè)置藍(lán)色前景色 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);
這次運(yùn)行之后就可以看到跟效果圖一樣的效果了。最后給一下源碼:CountDownTimerDemo
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
- Android使用CountDownTimer模擬短信驗(yàn)證倒計(jì)時(shí)
- Android CountDownTimer實(shí)現(xiàn)定時(shí)器和倒計(jì)時(shí)效果
- Android使用CountDownTimer類實(shí)現(xiàn)倒計(jì)時(shí)鬧鐘
- Android實(shí)現(xiàn)倒計(jì)時(shí)CountDownTimer使用詳解
- Android 列表倒計(jì)時(shí)的實(shí)現(xiàn)的示例代碼(CountDownTimer)
- Android利用CountDownTimer實(shí)現(xiàn)倒計(jì)時(shí)功能 Android實(shí)現(xiàn)停留5s跳轉(zhuǎn)到登錄頁(yè)面
- Android中CountDownTimer 實(shí)現(xiàn)倒計(jì)時(shí)功能
- Android CountDownTimer案例總結(jié)
相關(guān)文章
Android判斷現(xiàn)在所處界面是否為home主桌面的方法
這篇文章主要介紹了Android判斷現(xiàn)在所處界面是否為home主桌面的方法,涉及Android界面判斷的相關(guān)技巧,需要的朋友可以參考下2015-05-05Android實(shí)現(xiàn)打開手機(jī)淘寶并自動(dòng)識(shí)別淘寶口令彈出商品信息功能
最近項(xiàng)目經(jīng)理給我們安排一個(gè)活兒,基于Android開發(fā)實(shí)現(xiàn)打開手機(jī)淘寶,并自動(dòng)識(shí)別淘口令,彈出商品信息,今天小編就抽空給大家分享下這個(gè)需求是怎么實(shí)現(xiàn)的,需要的朋友參考下吧2017-11-11Android種使用Notification實(shí)現(xiàn)通知管理以及自定義通知欄實(shí)例(示例四)
本篇文章主要介紹了Android種使用Notification實(shí)現(xiàn)通知管理以及自定義通知欄實(shí)例,具有一定的參考價(jià)值,需要的朋友可以了解一下。2016-12-12基于Android實(shí)現(xiàn)答題倒計(jì)時(shí)功能
這篇文章主要介紹了基于Android實(shí)現(xiàn)答題倒計(jì)時(shí)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01EditText監(jiān)聽(tīng)方法,實(shí)時(shí)的判斷輸入多少字符
在EditText提供了一個(gè)方法addTextChangedListener實(shí)現(xiàn)對(duì)輸入文本的監(jiān)控。本文分享了EditText監(jiān)聽(tīng)方法案例,需要的朋友一起來(lái)看下吧2016-12-12Android應(yīng)用內(nèi)懸浮窗的實(shí)現(xiàn)方案示例
本篇文章主要介紹了Android應(yīng)用內(nèi)懸浮窗的實(shí)現(xiàn)方案示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08