先看一下效果:

在点击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实现的更多相关文章

  1. Android 自定义View合集

    自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...

  2. Android自定义View 画弧形,文字,并增加动画效果

    一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类   B ...

  3. (转)[原] Android 自定义View 密码框 例子

    遵从准则 暴露您view中所有影响可见外观的属性或者行为. 通过XML添加和设置样式 通过元素的属性来控制其外观和行为,支持和重要事件交流的事件监听器 详细步骤见:Android 自定义View步骤 ...

  4. Android 自定义View (五)——实践

    前言: 前面已经介绍了<Android 自定义 view(四)-- onMeasure 方法理解>,那么这次我们就来小实践下吧 任务: 公司现有两个任务需要我完成 (1)监测液化天然气液压 ...

  5. Android 自定义 view(四)—— onMeasure 方法理解

    前言: 前面我们已经学过<Android 自定义 view(三)-- onDraw 方法理解>,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法 推荐文章: htt ...

  6. Android 自定义 view(三)—— onDraw 方法理解

    前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...

  7. Android 自定义view(二) —— attr 使用

    前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...

  8. Android 自定义View

    Android 自定义View流程中的几个方法解析: onFinishInflate():从布局文件.xml加载完组件后回调 onMeasure() :调用该方法负责测量组件大小 onSizeChan ...

  9. Android自定义View之CircleView

    Android自定义View之CircleView 版权声明:本文为博主原创文章,未经博主允许不得转载. 转载请表明出处:http://www.cnblogs.com/cavalier-/p/5999 ...

随机推荐

  1. linux基本常用命令列举

    上回装完虚拟机中的linux系统了,进入找到terminal,打开命令行界面 pwd:展示目前为止绝对路径 cd cd~:跳转到/home/yy的位置 cd-:跳转到上一步的位置 cd path(绝对 ...

  2. HTML5和CSS3的一些新特性

    html5有哪些新特性.移除了那些元素?如何处理HTML5新标签的浏览器兼容问题?如何区分 HTML 和 HTML5? 新特性: 1. 拖拽释放(Drag and drop) 2. 语义化更好的内容标 ...

  3. Theoretical comparison between the Gini Index and Information Gain criteria

    Knowledge Discovery in Databases (KDD) is an active and important research area with the promise for ...

  4. 兼容性测试-如何使用IE11做低版本IE的兼容性测试

    操作步骤: 切换模式方法-按F12->展开显示->仿真菜单>在文档模式下拉框中选择IE版本

  5. 横向滑动的GridView

    思路: GridView行数设置为一行,外面套一个HorizontalScrollView,代码中设置GridView宽度 xml代码 <HorizontalScrollView android ...

  6. 2014年6月份第3周51Aspx源码发布详情

      基于知识树的多课程网络教学平台源码  2014-6-16 [VS2008]功能介绍:本平台是一个支持网上教学的网站,支持多个课程,教师可根据需要创建课程,进行课程结构.题库等的管理.   技术特色 ...

  7. ajax 中boolean值技巧

    // 利用判断 数据重复 function checkId () { var flag = true; $.ajax({ url: "", type: "post&quo ...

  8. hdu 2069

    #include "stdio.h" int main(){ int num,i1,i2,i3,i4,i5,n; int n1,n2,n3,n4,n5; while(~scanf( ...

  9. The next day to learn English

    if you smail when no  one else is around,you really meat it.

  10. C# Winform中无焦点状态下获取键盘输入或者USB扫描枪数据

    类文件: C#类文件 using System; using System.Collections.Generic; using System.Text; using System.Runtime.I ...