需求
项目中需要用到倒计时View,因为需求需要,所以不能只依靠本地计时。还需要网络请求数据之后,矫正时间。
所以本文的目标如下:
- 自定义字体
- 依赖网络的倒计时
- 时间矫正
- 倒计时的自动更新
最终效果如下:
分析
通过自定义控件去实现,然后通过HashMap存储对应奖期以及倒计时信息,然后通过定时的网络请求,去矫正计时。
因此本文设计控件继承自AppCompatTextView, 增加了设置初始时间,开始计时,更新计时,停止计时,取消计时,矫正计时,设置字体等若干方法。
实现
加载自定义字体
// 加载自定义字体
Typeface TEXT_TYPE;
try {
TEXT_TYPE = Typeface.createFromAsset(context.getAssets(), "fonts/Quartz_Regular.ttf");
} catch (Exception e) {
LogUtils.e("加载第三方字体失败。");
TEXT_TYPE = null;
}
if (TEXT_TYPE != null) {
setTypeface(TEXT_TYPE);
}
开始计时
开始计时,首先通过接口回调,对外暴露方法,方便进行开始前的准备工作。需要传入期次和结束时间两个参数。
更新时间通过handler去实现。
public void start(final int term_no, final long end_time) {
timeListener.timeStart();
contine_tag = true;
this.end_time = end_time;
this.term_no = term_no;
if (mTimerMap.get(term_no) == null) {
Timer timer = new Timer();
Term_view_bean term_view_bean = new Term_view_bean(timer, term_no, end_time);
mTimerMap.put(term_no, term_view_bean);
mTimerMap.get(term_no).getTimer().schedule(new TimerTask() {
@Override
public void run() {
if (contine_tag) {
if (is_over) {
this.cancel();
return;
}
mHandler.sendEmptyMessage(ticket_mode);
}
}
}, 0, 1000);
}
}
结束
结束计时,共分为2种,取消指定期次,和取消全部期次。
取消全部期次计时: 当不需要页面倒计时的时候调用,因为倒计时是采用Timer进行维护的,所以需要手动释放,以避免内存泄露相关事宜。
public void stopAll() {
try {
Iterator it = mTimerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
int key = (int) entry.getKey();
Term_view_bean bean = (Term_view_bean) entry.getValue();
bean.getTimer().cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
contine_tag = false;
is_over = true;
}
取消指定期次计时: 某一个期次奖期结束,根据期次号或者存储的值进行停止
public void stop(int position_term_no) {
if (mTimerMap.get(position_term_no) != null) {
mTimerMap.get(position_term_no).getTimer().cancel();
}
}
public void stopSaveValue(int value) {
Iterator it = mTimerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
int key = (int) entry.getKey();
if (key != value) {
Term_view_bean bean = (Term_view_bean) entry.getValue();
bean.getTimer().cancel();
}
}
}
时间显示格式化
/**
* 时间显示格式化
*
* @param second
* @return
*/
private String second2TimeSecond(long second) {
long days = second / (3600 * 24);
long hours = (second / 3600) % 24;
long minutes = (second % 3600) / 60;
long seconds = second % 60;
String showTime = "";
if (days > 0) {
showTime = days + "天 ";
}
if (hours > 0) {
if (hours < 10) {
showTime += "0" + hours + "时 ";
} else {
showTime += hours + "时 ";
}
}
if (minutes < 10) {
showTime += "0" + minutes + ":";
} else {
showTime += "" + minutes + ":";
}
if (seconds < 10) {
showTime += "0" + seconds;
} else {
showTime += "" + seconds;
}
return showTime;
}
修正倒计时
/**
* 修正当前倒计时信息
*/
public void updateTimer(final int term_no, final long end_time) {
this.end_time = end_time;
this.term_no = term_no;
if (mTimerMap.get(term_no) == null) {
start(term_no, end_time);
} else {
mTimerMap.get(term_no).setEnd_time(end_time);
}
}
使用
使用的时候,首先初始化,传入handler,然后定时进行网络请求即可呈现效果。
扫描二维码关注公众号,回复:
9051354 查看本文章
完整代码
完整代码如下:
public class CountdownTextView extends android.support.v7.widget.AppCompatTextView {
public static final int what_count_down_k3 = 1;
Map<Integer, Term_view_bean> mTimerMap;
private int term_no;
private int ticket_mode;
private TimeListener timeListener;
private long end_time = 0;
private boolean contine_tag = true;
private boolean is_over = false;
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case what_count_down_k3:// 10 分钟一期
if (end_time - TimeManager.getInstance().getServiceTime() <= Config.K3_R006_Time_End_sale * 1000) {
timeListener.buyDown();
}
if (end_time - TimeManager.getInstance().getServiceTime() <= 0) {
timeListener.timedown();
while (end_time - TimeManager.getInstance().getServiceTime() <= 0) {
term_no++;
end_time += 10 * 60 * 1000;
}
setTimeText();
try {
stopSaveValue(term_no);
} catch (Exception e) {
e.printStackTrace();
}
start(term_no, end_time);
} else {
setTimeText();
}
break;
}
}
};
public CountdownTextView(Context context) {
super(context);
initTextType(context);
}
public CountdownTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initTextType(context);
}
public CountdownTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initTextType(context);
}
private void setTimeText() {
setText(second2TimeSecond((end_time - TimeManager.getInstance().getServiceTime()) / 1000));
}
private void initTextType(Context context) {
// 加载自定义字体
Typeface TEXT_TYPE;
try {
TEXT_TYPE = Typeface.createFromAsset(context.getAssets(), "fonts/Quartz_Regular.ttf");
} catch (Exception e) {
LogUtils.e("加载第三方字体失败。");
TEXT_TYPE = null;
}
if (TEXT_TYPE != null) {
setTypeface(TEXT_TYPE);
}
}
public void init(int ticket_mode, TimeListener timeListener) {
mTimerMap = new HashMap<>();
this.timeListener = timeListener;
this.ticket_mode = ticket_mode;
}
public void start(final int term_no, final long end_time) {
timeListener.timeStart();
contine_tag = true;
this.end_time = end_time;
this.term_no = term_no;
if (mTimerMap.get(term_no) == null) {
Timer timer = new Timer();
Term_view_bean term_view_bean = new Term_view_bean(timer, term_no, end_time);
mTimerMap.put(term_no, term_view_bean);
mTimerMap.get(term_no).getTimer().schedule(new TimerTask() {
@Override
public void run() {
if (contine_tag) {
if (is_over) {
this.cancel();
return;
}
mHandler.sendEmptyMessage(ticket_mode);
}
}
}, 0, 1000);
}
}
public void stop(int position_term_no) {
if (mTimerMap.get(position_term_no) != null) {
mTimerMap.get(position_term_no).getTimer().cancel();
}
}
public void stopAll() {
try {
Iterator it = mTimerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
int key = (int) entry.getKey();
Term_view_bean bean = (Term_view_bean) entry.getValue();
bean.getTimer().cancel();
}
} catch (Exception e) {
e.printStackTrace();
}
contine_tag = false;
is_over = true;
}
public void stopSaveValue(int value) {
Iterator it = mTimerMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
int key = (int) entry.getKey();
if (key != value) {
Term_view_bean bean = (Term_view_bean) entry.getValue();
bean.getTimer().cancel();
}
}
}
/**
* 格式化
*
* @param second
* @return
*/
private String second2TimeSecond(long second) {
long days = second / (3600 * 24);
long hours = (second / 3600) % 24;
long minutes = (second % 3600) / 60;
long seconds = second % 60;
String showTime = "";
if (days > 0) {
showTime = days + "天 ";
}
if (hours > 0) {
if (hours < 10) {
showTime += "0" + hours + "时 ";
} else {
showTime += hours + "时 ";
}
}
if (minutes < 10) {
showTime += "0" + minutes + ":";
} else {
showTime += "" + minutes + ":";
}
if (seconds < 10) {
showTime += "0" + seconds;
} else {
showTime += "" + seconds;
}
return showTime;
}
/**
* 获取当前奖期
*
* @return
*/
public int getTerm_no() {
return term_no;
}
/**
* 修正当前倒计时信息
*/
public void updateTimer(final int term_no, final long end_time) {
this.end_time = end_time;
this.term_no = term_no;
if (mTimerMap.get(term_no) == null) {
start(term_no, end_time);
} else {
mTimerMap.get(term_no).setEnd_time(end_time);
}
}
public interface TimeListener {
void timedown();
void buyDown();
void timeStart();
}
private class Term_view_bean {
private Timer timer;// 定时器
private int integer;// 奖期
private long end_time;// 结束时间
public Term_view_bean() {
}
public Term_view_bean(Timer timer, int integer, long end_time) {
this.timer = timer;
this.integer = integer;
this.end_time = end_time;
}
public Timer getTimer() {
return timer;
}
public void setTimer(Timer timer) {
this.timer = timer;
}
public int getInteger() {
return integer;
}
public void setInteger(int integer) {
this.integer = integer;
}
public long getEnd_time() {
return end_time;
}
public void setEnd_time(long end_time) {
this.end_time = end_time;
}
}
}