您的位置:首页 > 其它

安卓CountDownTimer实现全民夺宝抢购倒计时和短信验证码倒计时

2016-04-21 23:43 681 查看
在sina里看到了什么全民夺宝的链接,然后忍不住1元的诱惑被坑了10多块,什么都没有抽到,但是还是有人抽到了不知道是不是坑爹的,然后也就动手做一下倒计时的功能。

先看全民夺宝:



说起这个功能是不是感觉so easy,然后就以此来搞2个倒计时效果,顺便也学习一下CountDownTimer的使用。

哈哈,看看今天实现的效果图:



回顾 常用的倒计时方式

方法一

Timer与TimerTask(Java实现)

public class timerTask extends Activity{
private int recLen = 11;
private TextView txtView;
Timer timer = new Timer();
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);

setContentView(R.layout.timertask);
txtView = (TextView)findViewById(R.id.txttime);

timer.schedule(task, 1000, 1000);       // timeTask
}
TimerTask task = new TimerTask() {
@Override
public void run() {

runOnUiThread(new Runnable() {      // UI thread
@Override
public void run() {
recLen--;
txtView.setText(""+recLen);
if(recLen < 0){
timer.cancel();
txtView.setVisibility(View.GONE);
}
}
});
}
};
}


方法二

TimerTask与Handler(不用Timer的改进型)

public class timerTask extends Activity{
private int recLen = 11;
private TextView txtView;
Timer timer = new Timer();

public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);

setContentView(R.layout.timertask);
txtView = (TextView)findViewById(R.id.txttime);

timer.schedule(task, 1000, 1000);       // timeTask
}

final Handler handler = new Handler(){
@Override
public void handleMessage(Message msg){
switch (msg.what) {
case 1:
txtView.setText(""+recLen);
if(recLen < 0){
timer.cancel();
txtView.setVisibility(View.GONE);
}
}
}
};

TimerTask task = new TimerTask() {
@Override
public void run() {
recLen--;
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
};
}


方法三

Handler与Message(不用TimerTask)

public class timerTask extends Activity{
private int recLen = 11;
private TextView txtView;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.timertask);
txtView = (TextView)findViewById(R.id.txttime);
Message message = handler.obtainMessage(1);     // Message
handler.sendMessageDelayed(message, 1000);
}
final Handler handler = new Handler(){
public void handleMessage(Message msg){         // handle message
switch (msg.what) {
case 1:
recLen--;
txtView.setText("" + recLen);
if(recLen > 0){
Message message = handler.obtainMessage(1);
handler.sendMessageDelayed(message, 1000);      // send message
}else{
txtView.setVisibility(View.GONE);
}
}
super.handleMessage(msg);
}
};
}


方法四

Handler与Thread(不占用UI线程)

public class timerTask extends Activity{
private int recLen = 11;
private TextView txtView;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.timertask);
txtView = (TextView)findViewById(R.id.txttime);
new Thread(new MyThread()).start();         // start thread
}
final Handler handler = new Handler(){          // handle
public void handleMessage(Message msg){
switch (msg.what) {
case 1:
recLen--;
txtView.setText("" + recLen);
}
super.handleMessage(msg);
}
};
public class MyThread implements Runnable{      // thread
@Override
public void run(){
while(recLen>0){
try{
Thread.sleep(1000);     // sleep1000ms
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}catch (Exception e) {
}


方法五

Handler与Runnable(最简单型)

public class timerTask extends Activity{
private int recLen = 11;
private TextView txtView;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.timertask);
txtView = (TextView)findViewById(R.id.txttime);
handler.postDelayed(runnable, 1000);
}

Handler handler = new Handler();
Runnable runnable = new Runnable() {
@Override
public void run() {
if(recLen>0){
recLen--;
}
txtView.setText("" + recLen);
handler.postDelayed(this, 1000);
}
};
}


回顾了以前最常使用的5种方法是不是觉得还是比较麻烦,要说最好的也就第5种。

CountDownTimer 实现倒计时功能

使用案列(简单)

/**
* 继承 CountDownTimer 防范
*
* 重写 父类的方法 onTick() 、 onFinish()
*/

class MyCountDownTimer extends CountDownTimer {
/**
* @param millisInFuture
*      表示以毫秒为单位 倒计时的总数
*      例如 millisInFuture=1000 表示1秒
* @param countDownInterval
*      表示 间隔 多少微秒 调用一次 onTick 方法
*      例如: countDownInterval =1000 ; 表示每1000毫秒调用一次onTick()
*
*/
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}

@Override
public void onFinish() {
.....//记时结束处理
}

@Override
public void onTick(long millisUntilFinished) {
.....//计时过程中的处理
}
}
}


开始倒计时使用:CountDownTimer .start();

关闭:CountDownTimer .cancle();

这里拿两种情况来实现这功能,顺便也做成2个自定义view来使用。

布局界面图:



先看布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context="com.losileeya.countdownmaster.MainActivity"
android:layout_marginTop="20dp"
android:gravity="center_horizontal"
android:orientation="vertical"
android:background="#AAA9AA">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="场景一:商品抢购"
android:textSize="24sp"
android:textColor="#D93552"
/>
<com.losileeya.countdownmaster.view.CommodityBuyView
android:id="@+id/commodityBuyView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="场景二:短信验证码"
android:textSize="24sp"
android:textColor="#D93552"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="vertical">
<EditText
android:id="@+id/et_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/code_bg"
android:hint="请输入手机号"
android:padding="10dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:maxLength="11"
android:textSize="16sp"/>
<LinearLayout
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<EditText
android:id="@+id/et_msg_code"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_weight="1"
android:background="@drawable/code_bg"
android:layout_marginLeft="50dp"
android:gravity="center"
/>
<com.losileeya.countdownmaster.view.TimeButton
android:id="@+id/time_button"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_gravity="center"
>
</com.losileeya.countdownmaster.view.TimeButton>
</LinearLayout>
</LinearLayout>
</LinearLayout>


我们先来 做短信验证码的倒计时功能:

思路就是:给按钮监听是否可点击,并且动态改变显示的文字,从而实现倒计时的效果。

package com.losileeya.countdownmaster.view;
import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import com.losileeya.countdownmaster.R;
/**
* 自定义控件,实现验证码按钮倒计时功能。
* losileeya
*
*/
public class TimeButton extends LinearLayout {
private Button timeButton;
private int default_time = 60*1000;//默认时间
private TimeButtonCallBack timeButtoncallback;//倒计时按钮回掉接口
private MyCountDownTimer mc; //倒计时线程
public TimeButton(Context context) {
this(context, null);
}

public TimeButton(Context context, AttributeSet attrs)    {
this(context, attrs, 0);
}
public TimeButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//把view和布局绑定
timeButton = (Button) inflater.inflate(R.layout.view_time_button, this).findViewById(R.id.time);
initListerner();
}

/**
* 暴露倒计时时间给使用者调
* @param millis
*/
public void setTime(int millis){
this.default_time= millis;
}
public void initListerner() {
timeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (timeButtoncallback != null) {
if (timeButtoncallback.Start()) {
// 手机号验证通过了,那么继续下面的操作。
} else {
// 手机号验证未通过,直接返回了,不执行下面的操作。
return;
}
} else {
// 回调接口为空,有问题,直接返回了,不执行下面的操作。
return;
}
timeButton.setClickable(false);
mc = new MyCountDownTimer(default_time, 1000);
mc.start(); //倒计时记时
}
});
}

public void setTimeButtonCallBack(TimeButtonCallBack timeButtoncallback) {
this.timeButtoncallback = timeButtoncallback;
}

/**
* 倒计时控件回调外部代码的接口。
*
*
*/
public interface TimeButtonCallBack {

/**
* 点击按钮后,开始计时前调用的方法。
*
* @return 返回true会开始计时,false会退出计时。
*/
public boolean Start();

/**
* 结束啦。
*/
public void End();

/**
* 数字发生变化了。
*
* @param num
* @return
*/
public void numChanged(int num);

}
/**
* 继承 CountDownTimer 防范
*
* 重写 父类的方法 onTick() 、 onFinish()
*/

class MyCountDownTimer extends CountDownTimer {
/**
*
* @param millisInFuture
*      表示以毫秒为单位 倒计时的总数
*
*      例如 millisInFuture=1000 表示1秒
*
* @param countDownInterval
*      表示 间隔 多少微秒 调用一次 onTick 方法
*
*      例如: countDownInterval =1000 ; 表示每1000毫秒调用一次onTick()
*
*/
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}

@Override
public void onFinish() {
mc.cancel();
timeButton.setText("获取验证码");
timeButton.setClickable(true);
if (timeButtoncallback != null) {
timeButtoncallback.End();
}
}

@Override
public void onTick(long millisUntilFinished) {
timeButton.setText(millisUntilFinished/1000 + "秒后重新获取");
if (timeButtoncallback != null) {
timeButtoncallback.numChanged((int)millisUntilFinished/1000);
}
}
}
}


接下来是仿全民夺宝抢购倒计时功能:

实现思路:一整个view包含商品图片、商品描述,项目实际开发中会通过接口获取值,然后就是一个倒计时效果,倒计时结束后变为揭晓获奖答案。

package com.losileeya.countdownmaster.view;
import android.content.Context;
import android.os.CountDownTimer;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.losileeya.countdownmaster.R;
/**
* Created by losileeya on 2016/4/21.
*/
public class CommodityBuyView extends LinearLayout {
private TextView tv_goods_desc,tv_status,tv_awardee;
private MyCountDownTimer mc;
private LinearLayout ll_result;
private String awardee;
public CommodityBuyView(Context context) {
this(context, null);
}

public CommodityBuyView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public CommodityBuyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}

/**
* find 控件,初始化
* @param context
*/
private void initView(Context context) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//通过LayoutInflater  打气筒填补当前自定义view的布局。this表示attach到父控件
View view=inflater.inflate(R.layout.view_commodity_buying,this);
tv_goods_desc= (TextView)view.findViewById(R.id.tv_goods_desc);
tv_status= (TextView) view.findViewById(R.id.tv_status);
tv_awardee= (TextView) view.findViewById(R.id.tv_awardee);
ll_result= (LinearLayout) view.findViewById(R.id.ll_result);
tv_status=(TextView) view.findViewById(R.id.tv_status);
//这里为了显示出毫秒,所以0.1秒倒计时一次
mc = new MyCountDownTimer(280000, 100);
mc.start();
}
/**
* 继承 CountDownTimer 防范
*
* 重写 父类的方法 onTick() 、 onFinish()
*/

class MyCountDownTimer extends CountDownTimer {
/**
*
* @param millisInFuture
*      表示以毫秒为单位 倒计时的总数
*
*      例如 millisInFuture=1000 表示1秒
*
* @param countDownInterval
*      表示 间隔 多少微秒 调用一次 onTick 方法
*
*      例如: countDownInterval =1000 ; 表示每1000毫秒调用一次onTick()
*
*/
public MyCountDownTimer(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onFinish() {
tv_status.setText("揭晓中....");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//倒计时隐藏
tv_status.setVisibility(View.GONE);
//获奖结果显示
ll_result.setVisibility(View.VISIBLE);
//延迟5秒后公布获奖人
tv_awardee.setText(awardee);
}
}, 5000);
}
/**
* 处理时间倒计时进行页面刷新
* @param millisUntilFinished
*/
@Override
public void onTick(long millisUntilFinished) {
int ss = 1000;
int mi = ss * 60;
long minute = millisUntilFinished/ mi;//计算分钟
long second = (millisUntilFinished- minute * mi) / ss;//总时间-分钟的毫秒数得到秒数
long milliSecond = millisUntilFinished  - minute * mi - second * ss;//获得毫秒数
String strMinute = minute < 10 ? "0" + minute : "" + minute;//分钟
String strSecond = second < 10 ? "0" + second : "" + second;//秒
String strMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒不满十前面补0
strMilliSecond = milliSecond >100 ? strMilliSecond.substring(0,strMilliSecond.length()-1) : "" + strMilliSecond;////毫秒超过100显示前2位
//显示分秒毫秒的倒计时
tv_status.setText(strMinute + " 分 "+strSecond+"秒"+strMilliSecond);
}
}
/**
* 设置获奖人
* @param awardee
*/
public void setAwardee(String awardee){
this.awardee= awardee;
}
}


就写到这里吧,困觉。

总结

其实代码是很简单的,但是效果也还算可以的,项目过程中也或许用得到,至少很多人可能都不知道CountDownTimer这个东东,所以兴趣是最好的老师。如果你觉得还行的话,帮忙顶起来这将是对我最大的鼓励。

come on,enjoy it.

demo传送门: CountDownMaster

这里最后推荐一个倒计时控件:CountdownView
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: