Android自定义View之倒计时Countdown实现
先看一下效果:

在点击OK键之后,开始倒计时。
实现步骤
1、新建Android工程"CountdownView"

2、自定义Drawable
自定义View并没有直接的用户交互,简化起见,可以自定义实现一个drawable,作为ImageView的背景
观察一下View的构成,分为几个部分:
1. 外围圆环边界
2. 进度条
3. 内部圆形背景
4. 倒计时数字
另外,要画出这几个部分,画笔Paint肯定少不了
好了,自定义一个“CountdownDrawable”继承Drawable
public class CountdownDrawable extends Drawable {
//画笔
private Paint mPaint;
private RectF mArcRect;
//当前进度条进度
private float progress;
//边框圆颜色
private int outlineColor;
//内部背景圆颜色
private int innerColor;
//进度条颜色
private int ringColor;
//进度条宽度
private int ringWidth;
//倒计时数字
private int showNumber;
//数字颜色
private int textColor;
@Override
public void draw(Canvas canvas) {
// TODO Auto-generated method stub
}
@Override
public void setAlpha(int alpha) {
mPaint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return mPaint.getAlpha();
}
}
变量初始化:
public CountdownDrawable(int ringWidth, int outlineColor, int innerColor, int ringColor, int showNumber, int textColor) {
mPaint = new Paint();
mArcRect = new RectF();
this.outlineColor = outlineColor;
this.innerColor = innerColor;
this.ringColor = ringColor;
this.ringWidth = ringWidth;
this.showNumber = showNumber;
this.textColor = textColor;
}
3、 实现draw方法
public void draw(Canvas canvas) {
//获取view的边界
final Rect bounds = getBounds();
int size = bounds.height() > bounds.width() ? bounds.width() : bounds.height();
float outerRadius = ((size / 2) * 0.75f) * 0.937f;
float innerRadius = ((size / 2) * 0.75f) * 0.75f;
float offsetX = (bounds.width() - outerRadius * 2) / 2;
float offsetY = (bounds.height() - outerRadius * 2) / 2;
//画边框圆
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(1);
mPaint.setColor(outlineColor);
canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius, mPaint);
//画内部背景
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(innerColor);
canvas.drawCircle(bounds.centerX(), bounds.centerY(), innerRadius, mPaint);
//画倒计时数字
float textSize = innerRadius * 2 * 0.75f;
mPaint.setTextSize(textSize);
mPaint.setTextAlign(Align.CENTER);
mPaint.setColor(textColor);
float textX = bounds.centerX();
float textY = bounds.centerY() - (mPaint.descent() + mPaint.ascent()) / 2;
canvas.drawText(Integer.toString(showNumber), textX, textY, mPaint);
//画进度条
int halfRingWidth = ringWidth / 2;
float arcX0 = offsetX + halfRingWidth;
float arcY0 = offsetY + halfRingWidth;
float arcX = offsetX + outerRadius * 2 - halfRingWidth;
float arcY = offsetY + outerRadius * 2 - halfRingWidth;
mPaint.setColor(ringColor);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(ringWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mArcRect.set(arcX0, arcY0, arcX, arcY);
canvas.drawArc(mArcRect, 89, progress, false, mPaint);
}
4、 设置进度条及倒计时数字
public float getProgress() {
return progress / PROGRESS_FACTOR;
}
public void setProgress(float progress) {
this.progress = progress * PROGRESS_FACTOR;
invalidateSelf();
}
public int getShowNumber() {
return showNumber;
}
public void setShowNumber(int showNumber) {
this.showNumber = showNumber;
invalidateSelf();
}
5、 在Activity中完成drawable的使用
首先定义一个ImageView,设置其图片为刚刚定义的drawable
mIv = (ImageView)findViewById(R.id.iv);
mCdDrawable = new CountdownDrawable(getResources().getDimensionPixelSize(R.dimen.drawable_ring_size), getResources().getColor(R.color.dark_grey), getResources().getColor(R.color.brightly_grey)
, getResources().getColor(R.color.holo_green_light), 5, getResources().getColor(R.color.red));
mIv.setImageDrawable(mCdDrawable);
各颜色定义如下:
<dimen name="drawable_ring_size">4dp</dimen> <color name="dark_grey">#FF54585A</color>
<color name="holo_green_light">#FF99CC00</color>
<color name="brightly_grey">#CF9EA2A2</color>
<color name="red">#FFE61E27</color>
使用属性动画,计算进度条progress及倒计时数字showNumber
private Animator prepareAnimator() {
AnimatorSet animation = new AnimatorSet();
// 进度条动画
ObjectAnimator progressAnimator = ObjectAnimator.ofFloat(mCdDrawable, "progress", 1f, 0f);
progressAnimator.setDuration(5000);
progressAnimator.setInterpolator(new LinearInterpolator());
progressAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
mIv.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animation) {
mIv.setVisibility(View.GONE);
}
});
// 居中的倒计时数字
ObjectAnimator showNumberAnimator = ObjectAnimator.ofInt(mCdDrawable, "showNumber", 5, 0);
showNumberAnimator.setDuration(5000);
showNumberAnimator.setInterpolator(new LinearInterpolator());
animation.playTogether(progressAnimator, showNumberAnimator);
return animation;
}
最后在button中添加点击事件
private View.OnClickListener mBtnOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mAnimator != null) {
mAnimator.cancel();
}
mIv.setVisibility(View.VISIBLE);
mAnimator = prepareAnimator();
mAnimator.start();
}
};
完整工程代码放到了github上
Android自定义View之倒计时Countdown实现的更多相关文章
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android自定义View 画弧形,文字,并增加动画效果
一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类 B ...
- (转)[原] Android 自定义View 密码框 例子
遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...
- Android 自定义View (五)——实践
前言: 前面已经介绍了<Android 自定义 view(四)-- onMeasure 方法理解>,那么这次我们就来小实践下吧 任务: 公司现有两个任务需要我完成 (1)监测液化天然气液压 ...
- Android 自定义 view(四)—— onMeasure 方法理解
前言: 前面我们已经学过<Android 自定义 view(三)-- onDraw 方法理解>,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法 推荐文章: htt ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
- Android 自定义view(二) —— attr 使用
前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...
- Android 自定义View
Android 自定义View流程中的几个方法解析: onFinishInflate():从布局文件.xml加载完组件后回调 onMeasure() :调用该方法负责测量组件大小 onSizeChan ...
- Android自定义View之CircleView
Android自定义View之CircleView 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com/cavalier-/p/5999 ...
随机推荐
- [转]SPICE仿真软件基础(整理)
现在常用的SPICE仿真软件为方便用户使用都提供了较好的用户界面,在用仿真库中的元器件连成原理图后就可以进行仿真(当然要设置必要的仿真参数),但实际上只是用原理图自动产生了SPICE的格式语句,还是要 ...
- OpenLDAP安装
参考: http://54im.com/openldap/centos-6-yum-install-openldap-phpldapadmin-tls-%E5%8F%8C%E4%B8%BB%E9%85 ...
- 遍历所有表,取每个表的MAXID更新到ID控制表
) Declare @TID int DECLARE Temp_Cursor1 Cursor--定义游标 FOR SELECT Name FROM Sys_Entity OPEN Temp_Curso ...
- android-studio的gradle plugin配置相关的一些记录
感觉就是越高的Gradle版本对应的plugin越高. 你妹的,是不是2.10版本低于2.2版本,我还以为是2.10版本高于2.8.2.9版本呢.每次用2.10版本构建,用1.2.2等都不行.提示最低 ...
- Android sdk环境配置
1.环境搭建 1.1.JDK安装 1.2.Eclipse安装 1.3.Android SDK安装 1.4.ADT安装 1.5.创建AVD 详细细节 http://www.cnblogs.com/s ...
- 小型资源管理器,IO操作,读取和写入文件和目录的常用操作
解决方案: 小总结: 用IO流,的file,DirectoryInfo的方法绑定Treeview控件上和删除,读取, 可以熟练掌握一下IO流 主页面: private void Form1_Load( ...
- [蟒蛇菜谱]Python函数参数传递最佳实践
将函数作为参数传递,同时将该函数需要的参数一起传递.可参考threading.Timer的处理方式: class threading.Timer(interval, function, args=[] ...
- 有关attribute和property,以及各自对select中option的影响
这个问题老生常谈,但是直到现在我依旧时常会把它搞混.下面列一些各自的特性. attribute property 设置方法 option.setAttribute('selected', true ...
- 新手码农浅谈观察者模式(java语言简单实现)
一:什么是观察者模式: 官方定义:定义对象间一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 举个例子,很多人都会订阅天气预报,当气象台获得明天的天气情况( ...
- React Native 的ES5 ES6写法对照表
模块 引用 在ES5里,如果使用CommonJS标准,引入React包基本通过require进行,代码类似这样: //ES5 var React = require("react" ...