Android 自定义view和属性动画实现充电进度条效果

近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和自定义view的方式来完成这个功能,将它开源出来,供有需要的人了解一下相关的内容。

本次实现的功能类似下面的效果:

接下来便详细解析一下如何完成这个功能,了解其中的原理,这样就能举一反三,实现其他类似的动画效果了。

详细代码请看大屏幕

https://github.com/crazyandcoder/ChargeProgress

图形解析

一般,我们自定义view时,是将该view进行化解,分成一个一个小部分,然后在重叠起来进行绘制,对于这个项目,也是按照相同的步骤进行。我们用Word来简单解析一下该动画所包含的基本结构。

对于这个充电进度view,我将它分成了ABCD四个部分,下面来详细说明各个部分的组成。

A部分

对于A而言,它是位于整个view的顶部,居中显示,是一个圆角矩形。

B部分

对于B而言,它是整个view的重要组成部分,包含C和D两部分,其中B主要属性就是背景色的设置。

C部分

对于C而言,C就是每一个进度的样式,显示的是未完成的进度条样式。

D部分

对于D而言,它跟C是一样的,只不过是已经完成的进度样式,区别在于颜色的不一样。

其实,这个进度view图形结构还是比较简单的,只是一些简单的矩形,组合而成,因此对于以上的分析,我们轻易的得出一些重要的属性。

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="charging_progress">
<!--item个数-->
<attr name="cgv_item_count" format="integer" />
<!--边界宽度-->
<attr name="cgv_border_width" format="dimension" />
<!--边界颜色-->
<attr name="cgv_border_color" format="color" />
<!--圆角半径-->
<attr name="cgv_border_cornor_radius" format="dimension" />
<!--充电内每个进度item模块的宽度-->
<attr name="cgv_item_width" format="dimension" />
<!--充电内每个进度item模块的高度-->
<attr name="cgv_item_height" format="dimension" />
<!--充电内每个进度item模块的前景色,充电中的颜色-->
<attr name="cgv_item_charging_src" format="color" />
<!--充电内每个进度item模块的背景色,未充电的颜色-->
<attr name="cgv_item_charging_background" format="color" />
<!--view 的背景-->
<attr name="cgv_background" format="color" />
</declare-styleable>
</resources>

对于以上属性,我们在自定义view的时候需要在xml文件中进行设置,如果没有设置的话,我们给出一个默认。然后我们在代码中进行获取这些属性值。

//边界宽度
private float border_width;
//item个数
private int item_count;
//边界宽度
private float item_width;
//边界高度
private float item_height;
//view内部的进度前景色
private int item_charging_src;
//view内部的进度背景色
private int item_charging_background;
//view背景色
private int background;
//<!--边界颜色-->
private int border_color;
//圆角半径
private float border_cornor_radius;
//获取xml中设定的属性值
TypedArray array = mContext.obtainStyledAttributes(attrs, R.styleable.charging_progress);
border_width = array.getDimension(R.styleable.charging_progress_cgv_border_width, dp2px(2));
item_height = array.getDimension(R.styleable.charging_progress_cgv_item_height, dp2px(10));
item_width = array.getDimension(R.styleable.charging_progress_cgv_item_width, dp2px(20));
item_charging_src = array.getColor(R.styleable.charging_progress_cgv_item_charging_src, 0xffffea00);
item_charging_background = array.getColor(R.styleable.charging_progress_cgv_item_charging_background, 0xff544645);
background = array.getColor(R.styleable.charging_progress_cgv_background, 0xff463938);
border_color = array.getColor(R.styleable.charging_progress_cgv_border_color, 0xffb49d7c);
border_cornor_radius = array.getDimension(R.styleable.charging_progress_cgv_border_cornor_radius, dp2px(2));
item_count = array.getInt(R.styleable.charging_progress_cgv_item_count, 10);
array.recycle();

已经获取了自定义属性的值,那么接下来,我们就来具体绘制这些组合图形。

对于一个自定义view,首先要做的就是测量view的大小,而本项目中view的宽度和高度,宽度是好计算的,我们设置view的宽度等于item_widht 乘以2 。但是对于高度的话,因为我们设置了progress的级数,也就是item_count,也设置了item的高度和宽度,所以对于高度,我们可以通过计算item_count 乘以 item_height,再加上间隔数和顶部矩形的就是整个view的高度。同时,我们设定,顶部矩形的高度等于item_height,宽度等于item_widht的一半,中间间隔等于item_height 除以2

/**
* 测量view的宽和高,
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//总间隔数=(item_count+1) 乘以间隔高度(间隔高度等于item_height的一半)
//总数=item_count 乘以 item_height + 总间隔数 + 顶部一个矩形(高度等于item的高度,宽度等于item的宽度的一半)
mHeight = (int) (item_count * item_height + (item_count + 1) * item_height / 2 + item_height);
mWidth = (int) (2 * item_width);
setMeasuredDimension(mWidth, mHeight);
}

有了上面的设置,接下来我们就可以按部就班的画图了。

对于坐标中心点是设定在左上角,也就是(0,0)处。

画顶部矩形

知道了坐标系的原点,那么顶部矩形的坐标就可以计算了。

首先设置画笔。

mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(border_width);
mPaint.setColor((border_color));

由于顶部矩形的width等于item_widht的一半,所以它的width等于整个view的width的1/6,

int left = mWidth * 3 / 8;
int top = 0;
int right = 5 * mWidth / 8;
int bottom = (int) item_height / 2;
//顶部的矩形
RectF topRect = new RectF(left, top, right, bottom);
canvas.drawRoundRect(topRect, border_cornor_radius, border_cornor_radius, mPaint);

接下来绘制底部的矩形,也就是包含进度item的矩形

//总的进度背景
RectF border = new RectF(0, bottom, mWidth, mHeight);
canvas.drawRoundRect(border, border_cornor_radius, border_cornor_radius, mPaint);

接下来绘制每个item的矩形,对于每个item的坐标,实际上是有规律可循的。

//绘制所有的进度
for (int i = 1; i <= item_count; i++) {
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor((item_charging_background));
RectF backRect = new RectF(mWidth / 4,
(i + 1) * item_height / 2 + (i - 1) * item_height,
3 * mWidth / 4,
item_height / 2 + i * (3 * item_height / 2));
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
}

绘制动画

对于交流动画,就是从进度0到100的动画显示,依次显示。其实也是对于坐标的计算而已。接下来最终要的功能就是动画的使用了,我们使用的是属性动画呢?因为,常规的动画它不支持啊,很简单。

对于Android属性动画的学习,可以查看这篇文章,稍微了解一下。《Android动画了解》

1、交流动画

/**
* 绘制交流动画
*
* @param canvas
*/
private void drawACAnimaiton(Canvas canvas) {
int j = getProgress() / item_count;
//已经充好的进度
for (int i = item_count; i >= (item_count - j); i--) {
RectF backRect = new RectF(mWidth / 4,
(i + 1) * item_height / 2 + (i - 1) * item_height,
3 * mWidth / 4,
item_height / 2 + i * (3 * item_height / 2));
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(item_charging_src);
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
}
}

我们首先获取当前的进度,然后依次给它填充背景,这就是已完成的进度表示。

然后使用动画即可,我们设置进度为100,也就是充满,然后设置动画时间是10秒钟,对于下面的动画执行原理是什么呢?其实很简单,获取当前的进度,然后从0开始,依次绘制进度,知道绘制的进度为100就是总的进度,最后再循环执行动画即可。

/**
* 设置交流动画
*/
public void setACAnimation() {
chargeType = AC;
animAC = ObjectAnimator.ofInt(this, "progress", 100);
animAC.setDuration(10 * 1000);
animAC.setInterpolator(new LinearInterpolator());
animAC.setRepeatCount(ValueAnimator.INFINITE);
animAC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
invalidate();
}
});
animAC.start();
}

2、直流动画

对于直流动画就稍微比较复杂了。当我们设置了进度后,需要我们预先绘制已完成的进度,然后在下一个进度进行闪烁表示动画,那么该如何完成呢?

首先看绘制代码:

/**
* 直流动画
*
* @param canvas
*/
private void drawDCAniamtion(Canvas canvas) {
int j = getProgress() / item_count;
//已经充好的进度
for (int i = item_count; i > (item_count - j); i--) {
RectF backRect = new RectF(mWidth / 4,
(i + 1) * item_height / 2 + (i - 1) * item_height,
3 * mWidth / 4,
item_height / 2 + i * (3 * item_height / 2));
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(item_charging_src);
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
}
//下一个进度,隐藏和显示交替执行动画
int i = item_count - j;
if (i > 0) {
RectF backRect = new RectF(mWidth / 4,
(i + 1) * item_height / 2 + (i - 1) * item_height,
3 * mWidth / 4,
item_height / 2 + i * (3 * item_height / 2));
mPaint.setStyle(Paint.Style.FILL);
if (show) {
mPaint.setColor((item_charging_src));
} else {
mPaint.setColor((item_charging_background));
}
canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);
}
}

首先绘制已完成的进度,然后在绘制闪烁的部分。

/**
* 直流动画
*
* @param progress
*/
public void setDCAnimation(final int progress) {
chargeType = DC;
animatorDC = ValueAnimator.ofFloat(0, 1);
animatorDC.setInterpolator(new LinearInterpolator());
animatorDC.setDuration(1000);
animatorDC.setRepeatCount(-1);
animatorDC.setRepeatMode(ValueAnimator.RESTART);
animatorDC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
if (value > 0.5) {
show = true;
} else {
show = false;
}
setProgress(progress);
}
});
animatorDC.start();
}

到这里,就很明了了。对于直流动画,我们使用属性动画中这个ValueAnimator类,它的意思就是从0到1平滑的过渡,在设定的时间内。我们的原理是当达到0.5以上后就设定灰色进度,当小于0.5的话就设置亮色进度,然后在刷新一下view即可。

以上所述是小编给大家介绍的Android 自定义view和属性动画实现充电进度条效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android自定义View之圆形进度条式按钮

    介绍 今天上班的时候有个哥们问我怎么去实现一个按钮式的进度条,先来看看他需要实现的效果图. 和普通的圆形进度条类似,只是中间的地方有两个状态表示,未开始,暂停状态.而且他说圆形进度的功能已经实现了.那么我们只需要对中间的两个状态做处理就行了. 先来看看实现的效果图: 上面说了我们只需要处理中间状态的变化就可以了,对于进度的处理直接使用了弘洋文章中实现: http://blog.csdn.net/lmj623565791/article/details/43371299 下面开始具体实现. 具体实

  • Android自定义View仿华为圆形加载进度条

    View仿华为圆形加载进度条效果图 实现思路 可以看出该View可分为三个部分来实现 最外围的圆,该部分需要区分进度圆和底部的刻度圆,进度部分的刻度需要和底色刻度区分开来 中间显示的文字进度,需要让文字在View中居中显示 旋转的小圆点,小圆点需要模拟小球下落运动时的加速度效果,开始下落的时候慢,到最底部时最快,上来时速度再逐渐减慢 具体实现 先具体细分讲解,博客最后面给出全部源码 (1)首先为View创建自定义的xml属性 在工程的values目录下新建attrs.xml文件 <resourc

  • Android自定义View基础开发之图片加载进度条

    学会了Paint,Canvas的基本用法之后,我们就可以动手开始实践了,先写个简单的图片加载进度条看看. 按照惯例,先看效果图,再决定要不要往下看: 既然看到这里了,应该是想了解这个图片加载进度条了,我们先看具体用法,再看自定义View的实现: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.co

  • android ListView和ProgressBar(进度条控件)的使用方法

    ListView控件的使用:ListView控件里面装的是一行一行的数据,一行中可能有多列,选中一行,则该行的几列都被选中,同时可以触发一个事件,这种控件在平时还是用得很多的.使用ListView时主要是要设置一个适配器,适配器主要是用来放置一些数据.使用起来稍微有些复杂,这里用的是android自带的SimpleAdapter,形式如下:android.widget.SimpleAdapter.SimpleAdapter(Context context, List<? extends Map<

  • Android中实现Webview顶部带进度条的方法

    写这篇文章,做份备忘,简单滴展示一个带进度条的Webview示例,进度条位于Webview上面. 示例图如下: 主Activity代码: 复制代码 代码如下: package com.droidyue.demo.webviewprogressbar; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.View; import android.vi

  • Android自定义View实现带数字的进度条实例代码

    第一步.效果展示 图1.蓝色的进度条 图2.红色的进度条 图3.多条颜色不同的进度条 图4.多条颜色不同的进度条 第二步.自定义ProgressBar实现带数字的进度条 0.项目结构 如上图所示:library项目为自定义的带数字的进度条NumberProgressBar的具体实现,demo项目为示例项目以工程依赖的方式引用library项目,然后使用自定义的带数字的进度条NumberProgressBar来做展示 如上图所示:自定义的带数字的进度条的library项目的结构图 如上图所示:de

  • Android WebView线性进度条实例详解

    推荐阅读:Android Webview添加网页加载进度条实例详解 先给大家展示下效果图:这个效果图大家一看就懂,在生活经常见到 1.wevbview_progressbar.xml <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <!-- 背景 --> <item android:id="@android:id/background"&g

  • Android view自定义实现动态进度条

    Android  自定义view实现动态进度条 效果图: 这个是看了梁肖的demo,根据他的思路自己写了一个,但是我写的这个貌似计算还是有些问题,从上面的图就可以看出来,左侧.顶部.右侧的线会有被截掉的部分,有懂得希望能给说一下,改进一下,这个过程还是有点曲折的,不过还是觉得收获挺多的.比如通动画来进行动态的展示(之前做的都是通过Handler进行更新的所以现在换一种思路觉得特别好),还有圆弧的起止角度,矩形区域的计算等!关于绘制我们可以循序渐进,比如最开始先画圆,然后再画周围的线,最后设置动画

  • android自定义进度条渐变色View的实例代码

    最近在公司,项目不是很忙了,偶尔看见一个兄台在CSDN求助,帮忙要一个自定义的渐变色进度条,我当时看了一下进度条,感觉挺漂亮的,就尝试的去自定义view实现了一个,废话不说,先上图吧! 这个自定义的view,完全脱离了android自带的ProgressView,并且没使用一张图片,这样就能更好的降低程序代码上的耦合性! 下面我贴出代码  ,大概讲解一下实现思路吧! 复制代码 代码如下: package com.spring.progressview; import android.conten

  • Android Webview添加网页加载进度条实例详解

    推荐阅读:Android WebView线性进度条实例详解 最近在android项目中使用webview嵌套了一个抽奖活动网页,活动上线,运行良好(改了N次需求和突发bug),还好这种模式的活动,只需要修改网页,不需要重新打包发布市场,这也是这种模式开发的优势之一.后来据产品哥反馈说加载网页无进度提示,好吧,这个当时真没考虑这么多,这个要加加..想当然以为轻松搞定之....其实还是比轻松要复杂点... 1.首先自定义一个WebView控件 /** * 带进度条的Webivew * @author

随机推荐