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 ...
随机推荐
- vultr vps服务器存在的7个优势及选择原因
原本准备在第一篇文章的时候完整的新注册账户的,但是考虑到对于这款VPS主机的了解,还是先整理这篇关于网络上和我自己在使用vultr vps主机产品的时候可能自认为的优势之处,这样可以加强很多新用户对于 ...
- 初学者的python学习笔记2
本来想是先把作业二搞定的,结果发现作业二用的字典,一脸懵逼,还是先搞定第二课吧.其实第二课和第一课内容差不多,据说是第一课的老师去美国了……不管怎么样先整理一下吧. ----------------- ...
- linux 两个文件合并
可以使用cat命令,有两种实现的方式,一种将两个文件合并的到一个新的文件,另一种将一个文件追加到另一个文件的末尾. 方法一:使用cat命令从文件中读入两个文件,然后将重定向到一个新的文件.这种方法可以 ...
- css3实现头像旋转功能(超easy!!!)
简单好玩的头像旋转功能 html结构 <body> <img src="https://a-ssl.duitang.com/uploads/item/201604/29/2 ...
- oracle 用户创建这个挺靠谱
CREATE TEMPORARY TABLESPACE test_tempTEMPFILE 'C:\oracle\product\10.1.0\oradata\orcl\test_temp01.dbf ...
- Activity 生命周期
Activity 的四种基本状态 1.运行态(Running) Activity 处于屏幕最前端,用户可见且获得焦点. 2.暂停态(Paused) Activity被置于后台,用户可见,但失去焦点 3 ...
- 移动混合开发之android文件管理demo
框架采用cordova,android编译环境为android studio.系统为mac,cordova 环境搭建参考网址:http://cordova.apache.org/docs/en/5.0 ...
- “用户、组或角色'XXX'在当前数据库中已存在”问题
一般在还原数据库后,给这个数据库添加一个登录名时出现. 例如数据库备份文件中已经包含了用户abc,现在还原了数据库,然后发现现有数据库中没有abc这个用户,想要新建一个abc用户,作为该数据库的own ...
- mariadb配置允许远程访问方式
首先配置允许访问的用户,采用授权的方式给用户权限 1 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'IDENTIFIED BY '123456' WITH GRAN ...
- Myeclipse闪退故障
Myeclipse在编辑代码是出现反复一个异常错误. Index out of bounds,而且窗口关闭后还是出现, 于是在任务管理器里强制关闭MyEclipse. 关闭后启动MyEclipse总是 ...