CountDownDigitalClock:倒计时的TextView
来源:互联网 发布:java兼职猪八戒网 编辑:程序博客网 时间:2024/06/03 18:04
http://www.cnblogs.com/over140/archive/2010/08/27/1809873.html
改了一下,但是输出格式未能实现自定义,原因在于下面的代码中显示时间差不正确,我不知道什么原因。
mFormat = "距离结束还有dd天kk小时mm分ss秒";//yyyy-MM-dd hh:mm:ss
mCalendar.setTimeInMillis(mTimeDistance);//为什么这样计算的时间不对???
setText(DateFormat.format(mFormat, mCalendar));
我只能退一步,将就着了,源码是这样的:
用法:
http://www.23code.com/circletimerview/
Android 倒计时控件,可以定义多种样式。
http://www.jcodecraeer.com/a/opensource/2015/1016/3586.html
CountdownView mCvCountdownViewTest1 = (CountdownView)findViewById(R.id.cv_countdownViewTest1);
mCvCountdownViewTest1.start(995550000); // 毫秒
<cn.iwgang.calendardemo.countdownview.CountdownView
android:id="@+id/cv_countdownViewTest4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
app:isHideTimeBackground="true"
app:isShowHour="true"
app:isShowMillisecond="true"
app:timeTextColor="#000000"
app:timeTextSize="25sp"
app:suffixTextColor="#000000"
app:suffixTextSize="15sp"
app:suffixHour=" 时 "
app:suffixMinute=" 分 "
app:suffixSecond=" 秒 "
app:suffixMillisecond=" 毫秒" />
改了一下,但是输出格式未能实现自定义,原因在于下面的代码中显示时间差不正确,我不知道什么原因。
mFormat = "距离结束还有dd天kk小时mm分ss秒";//yyyy-MM-dd hh:mm:ss
mCalendar.setTimeInMillis(mTimeDistance);//为什么这样计算的时间不对???
setText(DateFormat.format(mFormat, mCalendar));
我只能退一步,将就着了,源码是这样的:
import java.util.Calendar;import android.content.Context;import android.database.ContentObserver;import android.os.Handler;import android.os.SystemClock;import android.provider.Settings;import android.text.format.DateFormat;import android.util.AttributeSet;import android.util.Log;public class CountDownDigitalClock extends android.widget.DigitalClock {Calendar mCalendar;private final static String m12 = "h:mm aa";// h:mm:ss aaprivate final static String m24 = "k:mm";// k:mm:ssprivate FormatChangeObserver mFormatChangeObserver;private Runnable mTicker;private Handler mHandler;private boolean mTickerStopped = false;String mFormat;private long mDeadTime;private OnCountDownListener onCountDownListener;public CountDownDigitalClock(Context context) {super(context);initClock(context);}public CountDownDigitalClock(Context context, AttributeSet attrs) {super(context, attrs);initClock(context);}private void initClock(Context context) {if (mCalendar == null) {mCalendar = Calendar.getInstance();}mFormatChangeObserver = new FormatChangeObserver();getContext().getContentResolver().registerContentObserver(Settings.System.CONTENT_URI, true, mFormatChangeObserver);setFormat();}@Overrideprotected void onAttachedToWindow() {mTickerStopped = false;super.onAttachedToWindow();mHandler = new Handler();/** * requests a tick on the next hard-second boundary */mTicker = new Runnable() {public void run() {if (mTickerStopped)return;long mCurrentTime = System.currentTimeMillis();if (mCurrentTime >= mDeadTime) {if (onCountDownListener != null){onCountDownListener.onFinish();}return;}long mTimeDistance = mDeadTime - mCurrentTime;long between = mTimeDistance / 1000;// 转换成秒long day = between / (24 * 3600);long hour = between % (24 * 3600) / 3600;long minute = between % (24 * 3600) % 3600 / 60;long second = between % (24 * 3600) % 3600 % 60;String deadTimeStr = "距离结束还有" + day + "天" + hour + "小时"+ minute + "分" + second + "秒";setText(deadTimeStr);// mFormat = "距离结束还有dd天kk小时mm分ss秒";//yyyy-MM-dd hh:mm:ss// mCalendar.setTimeInMillis(mTimeDistance);//为什么这样计算的时间不对??? // setText(DateFormat.format(mFormat, mCalendar));if (onCountDownListener != null)onCountDownListener.onTick();invalidate();long now = SystemClock.uptimeMillis();long next = now + (1000 - now % 1000);mHandler.postAtTime(mTicker, next);}};mTicker.run();}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();mTickerStopped = true;}/** * Pulls 12/24 mode from system settings */private boolean get24HourMode() {return android.text.format.DateFormat.is24HourFormat(getContext());}private void setFormat() {if (get24HourMode()) {mFormat = m24;} else {mFormat = m12;}}private class FormatChangeObserver extends ContentObserver {public FormatChangeObserver() {super(new Handler());}@Overridepublic void onChange(boolean selfChange) {setFormat();}}/** * set the dead time * * @param deadtime */public void setDeadTime(long deadTime) {this.mDeadTime = deadTime;}public interface OnCountDownListener {public void onFinish();public void onTick();}public void setOnCountDownListener(OnCountDownListener onCountDownListener) {this.onCountDownListener = onCountDownListener;}}
用法:
mClock = (CountDownDigitalClock) findViewById(R.id.myClock); mClock.setDeadTime(getDeadTimeFromServer()); mClock.setOnCountDownListener(new CountDownDigitalClock.OnCountDownListener() {@Overridepublic void onFinish() {// TODO Auto-generated method stubshowToast("倒计时结束!!!");}@Overridepublic void onTick() {// TODO Auto-generated method stubLog.i("tag", "执行了"+(count++)+"次");}});private long getDeadTimeFromServer(){ Calendar mCalendar = Calendar.getInstance(); mCalendar.set(2012, 5-1, 18);//月份从0开始 mCalendar.set(Calendar.HOUR_OF_DAY, 13);//下午1点 mCalendar.set(Calendar.MINUTE, 0); mCalendar.set(Calendar.SECOND, 0); return mCalendar.getTimeInMillis();}
http://www.23code.com/circletimerview/
Android 倒计时控件,可以定义多种样式。
http://www.jcodecraeer.com/a/opensource/2015/1016/3586.html
CountdownView mCvCountdownViewTest1 = (CountdownView)findViewById(R.id.cv_countdownViewTest1);
mCvCountdownViewTest1.start(995550000); // 毫秒
<cn.iwgang.calendardemo.countdownview.CountdownView
android:id="@+id/cv_countdownViewTest4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
app:isHideTimeBackground="true"
app:isShowHour="true"
app:isShowMillisecond="true"
app:timeTextColor="#000000"
app:timeTextSize="25sp"
app:suffixTextColor="#000000"
app:suffixTextSize="15sp"
app:suffixHour=" 时 "
app:suffixMinute=" 分 "
app:suffixSecond=" 秒 "
app:suffixMillisecond=" 毫秒" />
import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.RectF;import android.os.CountDownTimer;import android.text.TextUtils;import android.util.AttributeSet;import android.view.View;/** * 倒计时View * Created by iWgang on 15/9/16. */public class CountdownView extends View { private Context mContext; private int mDay, mHour, mMinute, mSecond, mMillisecond; private OnCountdownEndListener mOnCountdownEndListener; private CountDownTimer mCountDownTimer; private boolean isShowDay; private boolean isShowHour; private boolean isShowMinute; private boolean isShowMillisecond; private boolean isHideTimeBackground; private boolean isShowTimeBgDivisionLine; private Paint mTimeTextPaint; private Paint mSuffixTextPaint; private Paint mTimeTextBgPaint; private Paint mTimeTextBgDivisionLinePaint; private RectF mDayBgRectF; private RectF mHourBgRectF; private RectF mMinuteBgRectF; private RectF mSecondBgRectF; private RectF mMillisecondBgRectF; private float mTimeTextWidth; private float mTimeTextHeight; private float mTimeTextSize; private float mTimeBgSize; private int mTimeTextColor; private int mTimeBgColor; private float mTimeBgRadius; private int mTimeBgDivisionLineColor; private float mTimeTextBaseY; private float mSuffixTextBaseY; private int mTimeBgDivisionLineSize; // 后缀 private boolean isHideLastSuffix; private String mSuffix; private String mSuffixDay; private String mSuffixHour; private String mSuffixMinute; private String mSuffixSecond; private String mSuffixMillisecond; private int mSuffixTextColor; private float mSuffixTextSize; private float mSuffixDayTextWidth; private float mSuffixHourTextWidth; private float mSuffixMinuteTextWidth; private float mSuffixSecondTextWidth; private float mSuffixMillisecondTextWidth; private int mSuffixGravity; public CountdownView(Context context) { this(context, null); } public CountdownView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CountdownView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CountdownView); mTimeBgColor = ta.getColor(R.styleable.CountdownView_timeBgColor, 0xFF444444); mTimeBgRadius = ta.getDimension(R.styleable.CountdownView_timeBgRadius, 0); isShowTimeBgDivisionLine = ta.getBoolean(R.styleable.CountdownView_isShowTimeBgDivisionLine, true); mTimeBgDivisionLineColor = ta.getColor(R.styleable.CountdownView_timeBgDivisionLineColor, Color.parseColor("#30FFFFFF")); mTimeTextSize = ta.getDimension(R.styleable.CountdownView_timeTextSize, sp2px(12)); mTimeTextColor = ta.getColor(R.styleable.CountdownView_timeTextColor, 0xFFFFFFFF); isHideTimeBackground = ta.getBoolean(R.styleable.CountdownView_isHideTimeBackground, false); isShowDay = ta.getBoolean(R.styleable.CountdownView_isShowDay, false); isShowHour = ta.getBoolean(R.styleable.CountdownView_isShowHour, true); isShowMinute = ta.getBoolean(R.styleable.CountdownView_isShowMinute, true); isShowMillisecond = ta.getBoolean(R.styleable.CountdownView_isShowMillisecond, false); mSuffixTextSize = ta.getDimension(R.styleable.CountdownView_suffixTextSize, sp2px(12)); mSuffixTextColor = ta.getColor(R.styleable.CountdownView_suffixTextColor, 0xFF000000); mSuffix = ta.getString(R.styleable.CountdownView_suffix); mSuffixDay = ta.getString(R.styleable.CountdownView_suffixDay); mSuffixHour = ta.getString(R.styleable.CountdownView_suffixHour); mSuffixMinute = ta.getString(R.styleable.CountdownView_suffixMinute); mSuffixSecond = ta.getString(R.styleable.CountdownView_suffixSecond); mSuffixMillisecond = ta.getString(R.styleable.CountdownView_suffixMillisecond); mSuffixGravity = ta.getInt(R.styleable.CountdownView_suffixGravity, 1); ta.recycle(); // 初始化画笔 initPaint(); // 初始化后缀 initSuffix(); // 测量时间文字高度 Rect rect = new Rect(); mTimeTextPaint.getTextBounds("00", 0, 2, rect); mTimeTextWidth = rect.width(); mTimeTextHeight = rect.height(); mTimeBgSize = mTimeTextWidth + (dp2px(2) * 4); // 初始化时间背景的RectF对象 initTimeBgRect(); } /** * 初始化画笔 */ private void initPaint() { // 初始化时间文字画笔 mTimeTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTimeTextPaint.setColor(mTimeTextColor); mTimeTextPaint.setTextAlign(Paint.Align.CENTER); mTimeTextPaint.setTextSize(mTimeTextSize); // 初始化分割文字画笔 mSuffixTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mSuffixTextPaint.setColor(mSuffixTextColor); mSuffixTextPaint.setTextSize(mSuffixTextSize); // 初始化时间背景画笔 mTimeTextBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTimeTextBgPaint.setStyle(Paint.Style.FILL); mTimeTextBgPaint.setColor(mTimeBgColor); // 初始化时间背景中间的分割线画笔 mTimeTextBgDivisionLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); mTimeTextBgDivisionLinePaint.setColor(mTimeBgDivisionLineColor); mTimeBgDivisionLineSize = dp2px(0.5f); mTimeTextBgDivisionLinePaint.setStrokeWidth(mTimeBgDivisionLineSize); } private void initSuffix() { boolean isSuffixNull = true; float mSuffixTextWidth = 0; if (!TextUtils.isEmpty(mSuffix)) { isSuffixNull = false; isHideLastSuffix = true; mSuffixTextWidth = mSuffixTextPaint.measureText(mSuffix); } if (isShowDay) { if (!TextUtils.isEmpty(mSuffixDay)) { mSuffixDayTextWidth = mSuffixTextPaint.measureText(mSuffixDay); } else { if (!isSuffixNull) { mSuffixDay = mSuffix; mSuffixDayTextWidth = mSuffixTextWidth; } } } if (isShowHour) { if (!TextUtils.isEmpty(mSuffixHour)) { mSuffixHourTextWidth = mSuffixTextPaint.measureText(mSuffixHour); } else { if (!isSuffixNull) { mSuffixHour = mSuffix; mSuffixHourTextWidth = mSuffixTextWidth; } } } if (isShowMinute) { if (!TextUtils.isEmpty(mSuffixMinute)) { mSuffixMinuteTextWidth = mSuffixTextPaint.measureText(mSuffixMinute); } else if (!isSuffixNull) { mSuffixMinute = mSuffix; mSuffixMinuteTextWidth = mSuffixTextWidth; } } if (!TextUtils.isEmpty(mSuffixSecond)) { mSuffixSecondTextWidth = mSuffixTextPaint.measureText(mSuffixSecond); } else if (isShowMillisecond && !isSuffixNull) { mSuffixSecond = mSuffix; mSuffixSecondTextWidth = mSuffixTextWidth; } if (isShowMillisecond && isSuffixNull && !TextUtils.isEmpty(mSuffixMillisecond)) { mSuffixMillisecondTextWidth = mSuffixTextPaint.measureText(mSuffixMillisecond); } } /** * 初始化时间背景的RectF对象 */ private void initTimeBgRect() { if (!isHideTimeBackground) { float mHourLeft = 0; float mMinuteLeft; float mSecondLeft; if (isShowDay) { // 显示天 // 初始化小时背景RectF mDayBgRectF = new RectF(0, 0, mTimeBgSize, mTimeBgSize); // 计算分钟x轴 mHourLeft = mTimeBgSize + mSuffixHourTextWidth; } if (isShowHour) { // 显示小时 // 初始化小时背景RectF mHourBgRectF = new RectF(mHourLeft, 0, mTimeBgSize + mHourLeft, mTimeBgSize); // 计算分钟x轴 mMinuteLeft = mHourLeft + mTimeBgSize + mSuffixHourTextWidth; } else { mMinuteLeft = mHourLeft; } if (isShowMinute) { // 显示分钟 // 初始化分钟背景RectF mMinuteBgRectF = new RectF(mMinuteLeft, 0, mTimeBgSize + mMinuteLeft, mTimeBgSize); // 计算秒钟x轴 mSecondLeft = mMinuteLeft + mTimeBgSize + mSuffixMinuteTextWidth; } else { mSecondLeft = mMinuteLeft; } // 初始化秒钟背景RectF mSecondBgRectF = new RectF(mSecondLeft, 0, mTimeBgSize + mSecondLeft, mTimeBgSize); if (isShowMillisecond) { // 计算毫秒x轴 float mMillisecondLeft = mTimeBgSize + mSuffixSecondTextWidth + mSecondLeft; // 初始化毫秒背景RectF mMillisecondBgRectF = new RectF(mMillisecondLeft, 0, mTimeBgSize + mMillisecondLeft, mTimeBgSize); } Paint.FontMetrics timeFontMetrics = mTimeTextPaint.getFontMetrics(); mTimeTextBaseY = mMinuteBgRectF.top + (mMinuteBgRectF.bottom - mMinuteBgRectF.top - timeFontMetrics.bottom + timeFontMetrics.top)/2 - timeFontMetrics.top; Paint.FontMetrics suffixFontMetrics = mSuffixTextPaint.getFontMetrics(); mSuffixTextBaseY = mMinuteBgRectF.top + (mMinuteBgRectF.bottom - mMinuteBgRectF.top - suffixFontMetrics.bottom + suffixFontMetrics.top)/2 - suffixFontMetrics.top; } else { Paint.FontMetrics suffixFontMetrics = mSuffixTextPaint.getFontMetrics(); float suffixFontHeight = suffixFontMetrics.bottom - suffixFontMetrics.top; switch (mSuffixGravity) { case 0: // top mSuffixTextBaseY = suffixFontHeight - 12; // TODO 待优化 break; case 1: // center mSuffixTextBaseY = mTimeTextHeight - (mTimeTextHeight - suffixFontHeight)/2 - suffixFontMetrics.bottom; break; case 2: // bottom mSuffixTextBaseY = mTimeTextHeight - (mTimeTextHeight - suffixFontHeight); break; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); float timeWidth = isHideTimeBackground ? mTimeTextWidth : mTimeBgSize; float width = timeWidth; width += (mSuffixDayTextWidth + mSuffixHourTextWidth + mSuffixMinuteTextWidth + mSuffixSecondTextWidth + mSuffixMillisecondTextWidth); if (isShowDay) { width += timeWidth; } if (isShowHour) { width += timeWidth; } if (isShowMinute) { width += timeWidth; } if (isShowMillisecond) { width += timeWidth; } setMeasuredDimension((int) width, (isHideTimeBackground ? (int) mTimeTextHeight : (int) mTimeBgSize)); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float mHourLeft = 0; float mMinuteLeft; float mSecondLeft; // 背景分割线Y坐标 float mTimeBgDivisionLineYPos = mTimeBgSize/2 + mTimeBgDivisionLineSize/2; if (isHideTimeBackground) { // 无背景 float mTextYPos = mTimeTextHeight; // 判断显示天 if (isShowDay) { // 画天文字 canvas.drawText(formatNum(mDay), mTimeTextWidth/2, mTextYPos, mTimeTextPaint); if (mSuffixDayTextWidth > 0) { // 画天后缀 canvas.drawText(mSuffixDay, mTimeTextWidth, mSuffixTextBaseY, mSuffixTextPaint); } // 计算小时x轴 mHourLeft = mTimeTextWidth + mSuffixDayTextWidth; } // 判断显示小时 if (isShowHour) { // 画小时文字 canvas.drawText(formatNum(mHour), mHourLeft + mTimeTextWidth/2, mTextYPos, mTimeTextPaint); if (mSuffixHourTextWidth > 0) { // 画小时后缀 canvas.drawText(mSuffixHour, mHourLeft + mTimeTextWidth, mSuffixTextBaseY, mSuffixTextPaint); } // 计算分钟x轴 mMinuteLeft = mHourLeft + mTimeTextWidth + mSuffixHourTextWidth; } else { mMinuteLeft = mHourLeft; } // 判断显示分钟 if (isShowMinute) { // 画分钟文字 canvas.drawText(formatNum(mMinute), mMinuteLeft + mTimeTextWidth/2 , mTextYPos, mTimeTextPaint); if (mSuffixMinuteTextWidth > 0) { // 画分钟后缀 canvas.drawText(mSuffixMinute, mMinuteLeft + mTimeTextWidth, mSuffixTextBaseY, mSuffixTextPaint); } // 计算秒钟x轴 mSecondLeft = mMinuteLeft + mTimeTextWidth + mSuffixMinuteTextWidth; } else { mSecondLeft = mMinuteLeft; } // 画秒钟文字 canvas.drawText(formatNum(mSecond), mSecondLeft + mTimeTextWidth/2, mTextYPos, mTimeTextPaint); if (mSuffixSecondTextWidth > 0) { // 画秒钟后缀 canvas.drawText(mSuffixSecond, mSecondLeft + mTimeTextWidth, mSuffixTextBaseY, mSuffixTextPaint); } if (isShowMillisecond) { // 计算毫秒x轴 float mMillisecondLeft = mSecondLeft + mTimeTextWidth + mSuffixSecondTextWidth; // 画毫秒文字 canvas.drawText(formatMillisecond(), mMillisecondLeft + mTimeTextWidth / 2, mTextYPos, mTimeTextPaint); if (mSuffixMillisecondTextWidth > 0) { // 画毫秒后缀 canvas.drawText(mSuffixMillisecond, mMillisecondLeft + mTimeTextWidth, mSuffixTextBaseY, mSuffixTextPaint); } } } else { // 有背景 // 判断显示天 if (isShowDay) { // 画天背景 canvas.drawRoundRect(mDayBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint); if (isShowTimeBgDivisionLine) { // 画天背景中间的横线 canvas.drawLine(0, mTimeBgDivisionLineYPos, mTimeBgSize, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint); } // 画天文字 canvas.drawText(formatNum(mHour), mDayBgRectF.centerX(), mTimeTextBaseY, mTimeTextPaint); if (mSuffixDayTextWidth > 0) { // 画天后缀 canvas.drawText(mSuffixDay, mTimeBgSize, mSuffixTextBaseY, mSuffixTextPaint); } // 计算小时x轴 mHourLeft = mTimeBgSize + mSuffixDayTextWidth; } // 判断显示小时 if (isShowHour) { // 画小时背景 canvas.drawRoundRect(mHourBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint); if (isShowTimeBgDivisionLine) { // 画小时背景中间的横线 canvas.drawLine(mHourLeft, mTimeBgDivisionLineYPos, mTimeBgSize + mHourLeft, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint); } // 画小时文字 canvas.drawText(formatNum(mHour), mHourBgRectF.centerX(), mTimeTextBaseY, mTimeTextPaint); if (mSuffixHourTextWidth > 0) { // 画小时后缀 canvas.drawText(mSuffixHour, mHourLeft + mTimeBgSize, mSuffixTextBaseY, mSuffixTextPaint); } // 计算分钟x轴 mMinuteLeft = mHourLeft + mTimeBgSize + mSuffixHourTextWidth; } else { mMinuteLeft = mHourLeft; } // 判断显示分钟 if (isShowMinute) { // 画分钟背景 canvas.drawRoundRect(mMinuteBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint); if (isShowTimeBgDivisionLine) { // 画分钟背景中间的横线 canvas.drawLine(mMinuteLeft, mTimeBgDivisionLineYPos, mTimeBgSize + mMinuteLeft, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint); } // 画分钟文字 canvas.drawText(formatNum(mMinute), mMinuteBgRectF.centerX(), mTimeTextBaseY, mTimeTextPaint); if (mSuffixMinuteTextWidth > 0) { // 画分钟后缀 canvas.drawText(mSuffixMinute, mMinuteLeft + mTimeBgSize, mSuffixTextBaseY, mSuffixTextPaint); } // 计算秒钟x轴 mSecondLeft = mMinuteLeft + mTimeBgSize + mSuffixMinuteTextWidth; } else { mSecondLeft = mMinuteLeft; } // 画秒钟背景 canvas.drawRoundRect(mSecondBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint); if (isShowTimeBgDivisionLine) { // 画秒钟背景中间的横线 canvas.drawLine(mSecondLeft, mTimeBgDivisionLineYPos, mTimeBgSize + mSecondLeft, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint); } // 画秒钟文字 canvas.drawText(formatNum(mSecond), mSecondBgRectF.centerX(), mTimeTextBaseY, mTimeTextPaint); if (mSuffixSecondTextWidth > 0) { // 画秒钟后缀 canvas.drawText(mSuffixSecond, mSecondLeft + mTimeBgSize, mSuffixTextBaseY, mSuffixTextPaint); } if (isShowMillisecond) { // 计算毫秒x轴 float mMillisecondLeft = mTimeBgSize + mSuffixSecondTextWidth + mSecondLeft; // 画毫秒背景 canvas.drawRoundRect(mMillisecondBgRectF, mTimeBgRadius, mTimeBgRadius, mTimeTextBgPaint); if (isShowTimeBgDivisionLine) { // 画毫秒背景中间的横线 canvas.drawLine(mMillisecondLeft, mTimeBgDivisionLineYPos, mTimeBgSize + mMillisecondLeft, mTimeBgDivisionLineYPos, mTimeTextBgDivisionLinePaint); } // 画毫秒文字 canvas.drawText(formatMillisecond(), mMillisecondBgRectF.centerX(), mTimeTextBaseY, mTimeTextPaint); if (mSuffixMillisecondTextWidth > 0) { // 画毫秒后缀 canvas.drawText(mSuffixMillisecond, mMillisecondLeft + mTimeBgSize, mSuffixTextBaseY, mSuffixTextPaint); } } } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); stop(); } /** * 启动倒计时 * @param millisecond 毫秒数 */ public void start(long millisecond) { if (millisecond <= 0) { return ; } updateShow(millisecond); if (null != mCountDownTimer) { mCountDownTimer.cancel(); mCountDownTimer = null; } mCountDownTimer = new CountDownTimer(millisecond, 10) { @Override public void onFinish() { // 倒计时结束 // 回调 if (null != mOnCountdownEndListener) { mOnCountdownEndListener.onEnd(); } } @Override public void onTick(long millisUntilFinished) { updateShow(millisUntilFinished); } }; mCountDownTimer.start(); } public void stop() { if (null != mCountDownTimer) mCountDownTimer.cancel(); } public void setShowHourView(boolean isShowHour) { this.isShowHour = isShowHour; invalidate(); } public void setShowMillisecondView(boolean isShowMillisecond) { this.isShowMillisecond = isShowMillisecond; invalidate(); } public void allShowZero() { mHour = 0; mMinute = 0; mSecond = 0; mMillisecond = 0; invalidate(); } public void setOnCountdownEndListener(OnCountdownEndListener onCountdownEndListener) { this.mOnCountdownEndListener = onCountdownEndListener; } private void updateShow(long ms) { mDay = (int)(ms / (1000 * 60 * 60 * 24)); mHour = (int)((ms % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); mMinute = (int)((ms % (1000 * 60 * 60)) / (1000 * 60)); mSecond = (int)((ms % (1000 * 60)) / 1000); mMillisecond = (int)(ms % 1000); invalidate(); } private String formatNum(int time) { return time < 10 ? "0"+time : String.valueOf(time); } private String formatMillisecond() { String retMillisecondStr; if (mMillisecond > 99) { retMillisecondStr = String.valueOf(mMillisecond).substring(0, 2); } else if (mMillisecond <= 9) { retMillisecondStr = "0" + mMillisecond; } else { retMillisecondStr = String.valueOf(mMillisecond); } return retMillisecondStr; } public interface OnCountdownEndListener { void onEnd(); } public int dp2px(float dpValue) { final float scale = mContext.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } public float sp2px(float spValue) { final float scale = mContext.getResources().getDisplayMetrics().scaledDensity; return spValue * scale; }}
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="CountdownView"> <attr name="timeBgColor" format="color" /> <attr name="timeBgRadius" format="dimension" /> <attr name="isShowTimeBgDivisionLine" format="boolean" /> <attr name="timeBgDivisionLineColor" format="color" /> <attr name="timeTextSize" format="dimension" /> <attr name="suffixTextSize" format="dimension" /> <attr name="timeTextColor" format="color" /> <attr name="suffixTextColor" format="color" /> <attr name="isHideTimeBackground" format="boolean" /> <attr name="isShowDay" format="boolean" /> <attr name="isShowHour" format="boolean" /> <attr name="isShowMinute" format="boolean" /> <attr name="isShowMillisecond" format="boolean" /> <attr name="suffix" format="string" /> <attr name="suffixDay" format="string" /> <attr name="suffixHour" format="string" /> <attr name="suffixMinute" format="string" /> <attr name="suffixSecond" format="string" /> <attr name="suffixMillisecond" format="string" /> <attr name="suffixGravity" > <enum name="top" value="0" /> <enum name="center" value="1" /> <enum name="bottom" value="2" /> </attr> </declare-styleable></resources>