- 浏览: 5819689 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (890)
- WindowsPhone (0)
- android (88)
- android快速迭代 (17)
- android基础 (34)
- android进阶 (172)
- android高级 (0)
- android拾遗 (85)
- android动画&效果 (68)
- Material Design (13)
- LUA (5)
- j2me (32)
- jQuery (39)
- spring (26)
- hibernate (20)
- struts (26)
- tomcat (9)
- javascript+css+html (62)
- jsp+servlet+javabean (14)
- java (37)
- velocity+FCKeditor (13)
- linux+批处理 (9)
- mysql (19)
- MyEclipse (9)
- ajax (7)
- wap (8)
- j2ee+apache (24)
- 其他 (13)
- phonegap (35)
最新评论
-
Memories_NC:
本地lua脚本终于执行成功了,虽然不是通过redis
java中调用lua脚本语言1 -
ZHOU452840622:
大神://处理返回的接收状态 这个好像没有监听到 遇 ...
android 发送短信的两种方式 -
PXY:
拦截部分地址,怎么写的for(int i=0;i<lis ...
判断是否登录的拦截器SessionFilter -
maotou1988:
Android控件之带清空按钮(功能)的AutoComplet ...
自定义AutoCompleteTextView -
yangmaolinpl:
希望有表例子更好。。。,不过也看明白了。
浅谈onInterceptTouchEvent、onTouchEvent与onTouch
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 aa private final static String m24 = "k:mm";// k:mm:ss private 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(); } @Override protected 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(); } @Override protected 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()); } @Override public 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() { @Override public void onFinish() { // TODO Auto-generated method stub showToast("倒计时结束!!!"); } @Override public void onTick() { // TODO Auto-generated method stub Log.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>
发表评论
-
NestedScrollView滚动到顶部固定子View悬停挂靠粘在顶端
2018-10-31 20:45 6993网上有一个StickyScrollView,称之为粘性Scro ... -
自定义Behavior实现AppBarLayout越界弹性效果
2017-03-31 09:33 10369一、继承AppBarLayout.Beha ... -
Android - 一种相似图片搜索算法的实现
2017-03-31 09:33 2622算法 缩小尺寸。 将图片缩小到8x8的尺寸,总共64个 ... -
使用SpringAnimation实现带下拉弹簧动画的 ScrollView
2017-03-30 11:30 2848在刚推出的 Support Library 25.3.0 里面 ... -
Android为应用添加角标(Badge)
2017-03-30 11:21 61751.需求简介 角标是什么意思呢? 看下图即可明了: 可 ... -
Android端与笔记本利用局域网进行FTP通信
2017-03-23 10:17 978先看图 打开前: 打开后: Activity类 ... -
PorterDuffColorFilter 在项目中的基本使用
2017-03-03 10:58 1354有时候标题栏会浮在内容之上,而内容会有颜色的变化,这时候就要求 ... -
ColorAnimationView 实现了滑动Viewpager 时背景色动态变化的过渡效果
2017-02-24 09:41 2220用法在注释中: import android.anima ... -
迷你轻量级全方向完美滑动处理侧滑控件SlideLayout
2017-01-16 16:53 2594纯手工超级迷你轻量级全方向完美滑动处理侧滑控件(比官方 sup ... -
Effect
2017-01-05 09:57 0https://github.com/JetradarMobi ... -
动态主题库Colorful,容易地改变App的配色方案
2016-12-27 14:49 2565Colorful是一个动态主题库,允许您很容易地改变App的配 ... -
对视图的对角线切割DiagonalView
2016-12-27 14:23 1118提供对视图的对角线切割,具有很好的用户定制 基本用法 ... -
仿淘宝京东拖拽商品详情页上下滚动黏滞效果
2016-12-26 16:53 3494比较常用的效果,有现成的,如此甚好!:) import ... -
让任意view具有滑动效果的SlideUp
2016-12-26 09:26 1707基本的类,只有一个: import android.a ... -
AdvancedWebView
2016-12-21 09:44 16https://github.com/delight-im/A ... -
可设置圆角背景边框的按钮, 通过调节色彩明度自动计算按下(pressed)状态颜色
2016-11-02 22:13 1920可设置圆角背景边框的的按钮, 通过调节色彩明度自动计算按下(p ... -
网络请求库相关
2016-10-09 09:35 62https://github.com/amitshekhari ... -
ASimpleCache一个简单的缓存框架
2015-10-26 22:53 2178ASimpleCache 是一个为android制定的 轻量级 ... -
使用ViewDragHelper实现的DragLayout开门效果
2015-10-23 10:55 3415先看一下图,有个直观的了解,向下拖动handle就“开门了”: ... -
保证图片长宽比的同时拉伸图片ImageView
2015-10-16 15:40 3733按比例放大图片,不拉伸失真 import android. ...
相关推荐
本文将深入探讨如何基于TextView实现一个倒计时功能,使指定的天数能够动态转化为“N天N小时N分钟N秒”的格式。这个自定义控件非常适合用在诸如活动倒计时、预约截止时间显示等场景。 首先,我们需要创建一个新的...
然而,有时候我们需要在TextView中实现更复杂的功能,比如计时器和倒计时器。这通常涉及到自定义View的开发,以扩展TextView的功能。以下是对这个主题的详细解释: 1. **自定义View基础**: 自定义View是Android...
1. 创建自定义View类:继承TextView或Button,添加倒计时逻辑。 2. 初始化:在构造函数中,获取并解析属性值,设置初始计时时间。 3. 开始倒计时:调用start方法启动倒计时,创建Handler并发送Runnable消息。 4. ...
compile 'org.sufficientlysecure:html-textview:4.0' } 例 < org.sufficientlysecure.htmltextview . HtmlTextView android : id = " @+id/html_text " android : layout_width = " match_parent
本教程将详细介绍如何仅使用TextView这一基本UI组件来高仿京东、淘宝等热门APP的活动倒计时效果。 首先,我们要了解倒计时的基本原理。在Android中,倒计时通常通过`java.util.Timer`或`CountDownTimer`类实现。`...
1. **自定义View**:倒计时控件通常基于`TextView`进行扩展,创建一个新的类,如`TimingTextView`,继承自`AppCompatTextView`,以便利用TextView的文本显示功能,同时添加倒计时逻辑。 2. **倒计时逻辑**:倒计时...
本示例项目——“仅使用TextView高仿京东淘宝各种APP活动倒计时样式Demo”旨在教你如何仅通过TextView组件,模仿京东、淘宝等热门电商应用中的活动倒计时效果。这个教程将带你深入理解Android UI设计和自定义View的...
开发者可能创建了一个继承自`TextView`或`View`的类,以便在倒计时过程中更新显示的内容,如剩余时间。 3. **线程管理**: 倒计时通常在后台线程执行,以避免阻塞主线程。源码可能使用了`Handler`、`Runnable`或者...
在Android应用开发中,有时我们需要实现一种功能,即在用户界面上显示3秒倒计时,用户可以选择在倒计时结束前点击界面来取消自动关闭,或者等待倒计时结束后,程序自动关闭界面。这样的设计可以增加用户体验,给用户...
为了实现仿京东的倒计时效果,我们需要自定义一个`View`或者`TextView`,并在此基础上扩展倒计时功能。关键在于如何将剩余时间转换为用户友好的格式,如“XX天XX小时XX分XX秒”。这需要对时间单位进行转换,将总毫秒...
App启动页倒计时功能是移动应用开发中常见的一种设计,它主要用于提升用户体验,通过显示一个带有倒计时的启动页,用户可以感知到应用正在准备就绪,从而减少等待的焦虑感。在这个示例中,采用了RxJava、RxLifecycle...
`HtmlTextView`是Android开发中的一个开源项目,主要用于在3.0及以上版本的TextView中解析并展示HTML代码,尤其在处理网络上的图像或图片时非常有用。然而,根据描述,这个项目在Android 7.0及更高版本上的表现可能...
首先,我们需要创建一个自定义的CountDown类,继承自View或TextView,以封装倒计时逻辑。这个类应该包含以下几个核心属性: 1. **总时长(totalTime)**:倒计时的总秒数。 2. **当前剩余时间(remainingTime)**:...
在Android开发中,实现验证码Button中的TextView倒计时效果是一个常见的需求,这通常涉及到界面交互和定时任务的处理。下面将详细介绍如何实现这一功能。 首先,我们创建一个自定义的Button,将TextVIew和Button的...
本知识点将详细介绍如何在Android中实现一个具有3D翻页效果的倒计时控件。这个控件不仅能够显示倒计时,还能通过上下翻转增加视觉吸引力,提升用户体验。 首先,我们需要理解倒计时控件的基本原理。在Android中,倒...
当倒计时结束,TextView会显示“倒计时结束!”。 对于样式变化,可以有以下几种方式: 1. **数字滚动效果**:你可以使用动画库实现数字逐位滚动的效果,使得倒计时更加动态。这通常通过自定义View或使用现有动画...
本教程将详细讲解如何在Android应用中使用`MaterialDialog`和`AlertDialog`实现倒计时功能,帮助开发者们提升用户体验。 首先,我们先了解`MaterialDialog`。`MaterialDialog`是Android的一款第三方库,它提供了...
这个类可能扩展了TextView或者自定义了一个ViewGroup,内部包含了一个TextView来显示倒计时。它可能提供了开始、暂停、重置倒计时的方法,并通过回调或者接口通知外部Activity或Fragment倒计时状态的变化。 通过...
2. **TextView的动态更新**:验证码倒计时的界面展示通常是一个TextView,显示剩余的时间,如“60秒后重新发送”。倒计时可以通过每隔一秒更新TextView的文本内容来实现。 3. **CountDownTimer**:Android SDK提供...