需求描述
倒计时功能是安卓app中常见的功能之一。比如发送验证码啊,距离比赛或者直播或者抢购还有xx时间啊等等。。。
既然这是一个常用控件,何不自定义之以复用之呢?那么话不多说,先来看看倒计时的基本效果:
倒计时效果
实现思路
- 构思结构
百米高楼平地起,边写边改并不是一个合格程序员的行为态度,首先需要构思该如何实现,需要提供哪些接口,关键的技术方案是啥等等,于是,有了如下的结构图:
类构造
选型:该控件的基本功能是展现文字,所以可以继承TextView
来进行相关的定制。
接口和主要技术方案:从类图中我们可以看到,主要是一个倒计时类,各种倒计时状态的监听以及各种属性值设置的接口
CountDownTimer
:使用安卓自带的原生计时工具类。
OnCountDownStartListener
:计时开始的监听。
OnCountDownTickListener
:计时每秒的回调监听。
mShowFormatTime
:是否返回格式化后的时间。
。。。
其他的一些接口类就是设置各种属性,看类名应该就能明白他的功能~
关键代码实现
接下来就是最关键的代码实现部分了!首先,定义回调接口类:
public interface OnCountDownStartListener {
void onStart();
}
public interface OnCountDownTickListener {
/**
* 每秒自己刷新textView
*
* @param untilFinished 剩余的时间
* @param showTime 可以直接使用的显示时间
* @param tv 控件
*/
void onTick(long untilFinished, String showTime, CountDownTextView tv);
}
public interface OnCountDownFinishListener {
void onFinish();
}
这些接口都是拱外部类实现,通过回调方式,来进行相关的操作。
整个倒计时控件的核心功能是计时,这里实现了正向计时和倒计时的功能,通过改变传参即可获取不同的结果,以下就是改控件最关键的count()
的功能函数,所有的操作都仰仗他了:
/**
* 计时方案
*
* @param time 计时时长
* @param timeUnit 时间单位
* @param isCountDown 是否是倒计时,false正向计时
*/
private void count(final long time, final long offset, final TimeUnit timeUnit, final boolean isCountDown) {
if (mCountDownTimer != null) {
mCountDownTimer.cancel();
mCountDownTimer = null;
}
setEnabled(mClickable);
// 转换成毫秒
final long millisInFuture = timeUnit.toMillis(time) + 500;
// 时间间隔为1s
long interval = TimeUnit.MILLISECONDS.convert(1, timeUnit);
if (offset == 0 && mOnCountDownStartListener != null) {
mOnCountDownStartListener.onStart();
}
if (TextUtils.isEmpty(mCountDownText)) {
mCountDownText = getText().toString();
}
mCountDownTimer = new CountDownTimer(millisInFuture, interval) {
@Override
public void onTick(long millisUntilFinished) {
long count = isCountDown ? millisUntilFinished : (millisInFuture - millisUntilFinished + offset);
long l = timeUnit.convert(count, TimeUnit.MILLISECONDS);
String showTime;
if (mShowFormatTime) {
showTime = generateTime(count, mIsShowCompleteTv);
} else {
showTime = String.valueOf(l);
}
if (mOnCountDownTickListener != null) {
mOnCountDownTickListener.onTick(l, showTime, CountDownTextView.this);
} else {
setText(String.format(mCountDownText, showTime));
}
}
@Override
public void onFinish() {
setEnabled(true);
mCountDownTimer = null;
if (!TextUtils.isEmpty(mNormalText)) {
setText(mNormalText);
}
if (mOnCountDownFinishListener != null) {
mOnCountDownFinishListener.onFinish();
}
}
};
mCountDownTimer.start();
}
从该段代码中可以看出,该函数主要是对原生的计时方法CountDownTimer
进行自定义封装,下面进行简单的解释:
- 创建计时器:
new CountDownTimer(millisInFuture, interval)
第一个参数是需要计时的时间,单位是毫秒;第二个参数是步长,此处为1000毫秒。
- 重写
CountDownTimer
的两个抽象类:
/**
* 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();
- 调用
该控件使用起来也很方便,首先在xml中进行定义,属性和TextView
都相同。
在代码中调用范例如下:
mCountDownTextView.setNormalText("倒计时控件")
.setBeforeIndex(label.length())
.setCountDownClickable(false)
.setIsShowComplete(true)
.setShowFormatTime(true)
.setOnCountDownTickListener(new CountDownTextView.OnCountDownTickListener() {
@Override
public void onTick(long untilFinished, String showTime, CountDownTextView tv) {
tv.setText(CustomerViewUtils.getMixedText(label + showTime, tv.getTimeIndexes(), true));
}
})
.setOnCountDownFinishListener(new CountDownTextView.OnCountDownFinishListener() {
@Override
public void onFinish() {
mCountDownTextView.setText("倒计时结束");
}
});
}
mCountDownTextView.startCountDown(countDowmNumber);
至此,一个完整的计时控件就完成了。谢谢各位能看到这里的看官~
源码地址
https://github.com/wx9265661/SmallDemos2
PS
我们看到效果中数字和文字是不同大小和颜色并且垂直居中的,这是通过自定义的SpannableString
来实现的。
网友评论