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 ...
随机推荐
- linux命令每日一练习 创建新文件 列出文件的时候带着行号
touch ××× nl ****
- wpf学习笔记
1.菜单:普通菜单.上下文菜单(ContextMenu) <Menu HorizontalAlignment="Left" Height="20" Ver ...
- 例子:Execution Model Sample - 应用状态保存
WP中,当你的应用被切换到后台 后,就进入了休眠状态,然后当一个应用从墓碑恢复时,如何恢复相应的状态,该例子就演示了如何保存和恢复UI以及APP相关状态. 这里有一篇很好的文章,请参见: http:/ ...
- python中if __name__ == '__main__': 的解析
当你打开一个.py文件时,经常会在代码的最下面看到if __name__ == '__main__':,现在就来介 绍一下它的作用. 模块是对象,并且所有的模块都有一个内置属性 __name__.一 ...
- 对contentoffset的理解
今天遇到一个问题,在写瀑布流时,竖屏的时候可以正常实现,在手机变成横屏后,总是显示不全. 最终查了两个小时,查到了导致这个的原因,是自己的判断cell是否在当前显示区域的方法写错了. 根本原因是没有很 ...
- sqlite学习
一鼓作气,今天继续学习了sqlite数据库在Xcode上的一些操作,主要是通过用oc代码进行salite表格的创建,删除,修改:以及对现有的表格数据进行增,删,改,查.虽然有点累,但是收获不小,感觉很 ...
- jQuery中的$.grep()方法的使用
标签: it 分类: jQuery grep()方法用于数组元素过滤筛选 grep(array,callback,invert) array:待过滤数组; callback:处理数组中的每个元素,并过 ...
- Linux内核分析——理解进程调度时机跟踪分析进程调度与进程切换的过程
20135125陈智威 +原创作品转载请注明出处 +<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验 ...
- Back to openGL!
#include <iostream> #include <windows.h> #include <gl/glut.h> #include <math.h& ...
- 黑苹果-IOS学习的开始
深知安装黑苹果的不易,在这里写一下关于我的Thinkpad E430c安装黑苹果教程(Mac版本:Yosemite 10.10.4),希望能够帮助有需要的朋友. 首先贴上我的电脑配置报表: ----- ...