原文链接:http://www.jianshu.com/p/0e25a10cb9f5

一款效果不错的动画,实现也挺简单的,推荐阅读学习~ —— 由 傻小孩b 分享

waveview

《Android 自定义波浪动画之"让进度浪起来~"》
转载请注明来自 傻小孩b_移动开发http://www.jianshu.com/users/d388bcf9c4d3)喜欢的可以关注我,不定期总结文章!您的支持是我的动力哈!

前言

首先贝塞尔曲线原理我在这里就不多说了,今天的重点还是讲下怎么实现波浪进度的实现原理,所以想要了解下贝塞尔曲线的程序yuan,请自己百度或者谷歌下哈,多谢合作~如果开发有什么问题也可以直接加入我的QQ群,详情请看我的个人简介。

演示

waveview.gif

WaveView 实现

(一)如何确定初始化的位置?

首先

在实现一个自定义View的时候,我们先来观察下想要的动画效果分为几个层次,如图所示:

1、向右的贝塞尔曲线,这里用“normal wave”来表示。
​ 作用:一直匀速向左的波浪曲线,作为波浪的前景

2、向右的贝塞尔曲线,这里用“rolling wave”来表示。
​ 作用:为了是波浪效果更佳逼真,所以添加了一个向右匀速的波浪曲线,并且滚动速度是“normal wave”的一半

3、波浪上升高度,这里用“wave height”来表示。
​ 作用:高度代表进度,可以根据设置的当前进度progress与最大进度max动态变化

其次

在这里我们先要来说下贝塞尔曲线应该怎么画。刚开始,有可能有程序yuan想过,画一个无限长(例如 Integer.MAX_VALUE),足够大了、固定周期的赛贝尔曲线,然后开启动画让他固定一个方向移动即可。的确,这种实现方式是可以的,但是感觉资源特别浪费,有可能还会出现内存溢出、响应异常等。所以答案:不建议!

当然,上面那个思路,我是有着手尝试过啦。最后还是择优选择了另一个思路,画出两个周期的贝塞尔曲线,当第一个贝塞尔曲线滑动到最后一个Point、接近第二个贝塞尔曲线的开始Point的时候,直接让他复位,恢复到最初时候的状态,这种绘画效果还是看起来比无限长的贝塞尔曲线效果没区别的。所以,每一次,我们需要计算4n +1个Point点,为什么要4n+1个点?下面图片说明:

Wave_1.png

最后

就是整个闭合区间的填充,如图所示:

wave_2.png

我们看下动画里面,初始化Point的关键代码:

    /**
* Initialize the original wave arts collection point , including normal wave ,rolling wave
*/
private void initPoint(){
if (isInitPoint){
isInitPoint = false;
pointList.clear();
shadpointList.clear(); WAVE_WIDTH = (float) (VIEW_WIDTH / 2.5);//这里开发 我直接设置波浪宽度为整个View的四分之一宽度
WAVE_HEIGHT = VIEW_HEIGHT/getWaveHeight();//波浪高度根据速度改变 dy = VIEW_HEIGHT;//Started from the bottom, when the height is rise, dy gradually reduce
//How many points calculated maximum support
int n = Math.round(VIEW_WIDTH / WAVE_WIDTH);
//start point for normal wave
int startX = 0;
Log.i(TAG,"begin point ("+DensityUtil.px2dip(mContext,startX)+" , "+DensityUtil.px2dip(mContext,dy)+")");
for (int i = 0; i < 4*n+1; i++) {
....
pointList.add(point);
}
// start point for rolling wave
startX = (int) VIEW_WIDTH;
for (int i = 0; i < 4*n+1; i++) {
....
shadpointList.add(point);
}
}
}

从上面的代码,我们可以观察到“normal wave”和“rolling wave”初始化Point各自存储在一个list上面,并且先根据波浪的宽度与整个View的宽度,计算出最多支持多少个初始化点(非控制点,一个周期最多三个Point) int n = Math.round(VIEW_WIDTH / WAVE_WIDTH); 因此便能计算出4n+1个point的初始化位置。

(二)如何浪起来?

我们直接定位在移动的动画方法flowingAnimation,根据代码,我们可以了解到使用了属性动画。

    private void flowingAnimation(){
ObjectAnimator animator = ObjectAnimator.ofFloat(this,"wave",0,100)
.setDuration(100);
animator.setRepeatCount(INFINITE);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
dx = dx + speed;
shd_dx = shd_dx + speed/2;//Half the speed of the normal waves ....
rerefreshPoints();//更新初始化点
postInvalidate();
}
})
;
animator.start();
}

从代码可以观察到,是属于一个无限循环的动画( animator.setRepeatCount(INFINITE);
),并且动态变化的是dx与shd_dx。因此可以直接观察在绘制onDraw里面,这两个动态变化的变量起了什么作用,以下截取部分onDraw的代码:

     for (int i = 0; i < pointList.size(); i++) {
int j = i + 1;
if (pointList.size() > i) {
float start1 = pointList.get(i).x;
wavePath.moveTo(start1, dy);//+dy
if (j % 2 == 0 && j >= 2) {
...
} else {
....
}}
}
....
for (int i = 0; i < shadpointList.size(); i++) {
int j = i + 1;
if (shadpointList.size() > i) {
float start1 = shadpointList.get(i).x + shd_dx;
shadPath.moveTo(start1, dy);//+dy
if (j % 2 == 0 && j >= 2) {
....
} else {
....
}
}
}

应该很明显可以观察到,dx是改变“normal wave”周期的起点,shd_dx是改变“rolling wave”周期起点,因此间接使贝塞尔曲线双向”浪起来“,有了波浪的效果。

(三)如何浮起来?

直接进入动画,观察动态变化的变量

    private void riseAnimation(){
....
if (dy > 0) {
...
ValueAnimator animator = ValueAnimator.ofFloat(0, s)
.setDuration(500);
animator.setInterpolator(new LinearInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
...
dy = s;
Log.i("yuan", "move m " + m + "dy " + dy);
}
});
animator.start();
beforDy = sum_dy - sum_dy * progressRatio;//save the last time the higher level
}
}

从代码可以观察到,动态变化的是dy,因此波浪浮动的高度由dy所决定,这里难点是这么计算出当我们设置max和progress的时候,动态去变化dy,这里我用一张图来解释下:

(四)回调监听

感觉回调监听感觉没有好说的~

首先WaveView是在onDraw进行回调的,但是这里来有个小问题,如果我们频繁的绘制,不处理的话每一次都会进行回调,这样也会造成不必要的浪费。因此这里,简单记录上次的进度,通过对比,不同才回调。

(五)总结

二十几天没总结,这期间搞了点东西,也经历了一个放松的国庆~当然,同志们也不能将开发落下~最后还是:我们也不能只是搬运代码的“程序猿”,更重要我们是需要写出更高质量的代码,创造的“程序猿”。下面附上源码,如果喜欢的话给个star哈~谢谢:

WaveView 让进度浪起来~

使用方法,可以直接上github看README

傻小孩b mark共勉,写给在成长路上奋斗的你

喜欢就为我点下喜欢、给我个github的star吧~ 感谢各位读者阅读。

Android 自定义波浪动画 --"让进度浪起来~"的更多相关文章

  1. Android 自定义帧动画

    Android 自定义帧动画 Android L : Android Studio 帧动画 和gif图片类似,顺序播放准本好的图片文件:图片资源在xml文件中配置好 将图片按照预定的顺序一张张切换,即 ...

  2. Android自定义窗口动画

    第一步,设置出现和消失的xml 1.在res/anim下创建enter_anim.xml,设置窗口出现的动画 <?xml version="1.0" encoding=&qu ...

  3. 实例源码--Android自定义Gallery动画效果

    相关文档与源码: 下载源码   技术要点: 1.自定义控件的使用 2.Gallery控件的使用实例 3.详细的源码注释 ...... 详细介绍: 1.自定义控件的使用 本套源码通过自定义控件的方式,继 ...

  4. Android自定义一款带进度条的精美按键

    Android中自定义View并没有什么可怕的,拿到一个需要自定义的View,首先要做的就是把它肢解,然后思考每一步是怎样实现的,按分析的步骤一步一步的编码实现,最后你就会发现达到了你想要的效果.本文 ...

  5. Android 自定义PopupWindow动画效果

    public class RollActivity extends Activity { private View view; private Button btn; private PopupWin ...

  6. Android 自定义漂亮的圆形进度条

    公司有这样一个需求,实现这个圆弧进度条 所以,现在就将它抽取出来分享 如果需要是圆帽的就将,下面这句代码放开即可 mRingPaint.setStrokeCap(Paint.Cap.ROUND);// ...

  7. Android 自定义View修炼-仿360手机卫士波浪球进度的实现

    像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用 ...

  8. android采用MVP漫画APP、适配刘海屏、小黄车主界面、录音波浪动画、综合APP等源码

    Android精选源码 一款采用MVP架构的仿完整漫画APP源码 Android适配刘海屏幕 基于Xmpp协议的即时通讯社交软件(客户端+服务端) Android小黄车(ofo)app主页菜单效果 一 ...

  9. Android 自定义 View 圆形进度条总结

    Android 自定义圆形进度条总结 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 微信公众号:牙锅子 源码:CircleProgress 文中如有纰漏,欢迎大家留言指出. 最近 ...

随机推荐

  1. ios编程之网络请求

    网络请求有GET请求和POST请求,get和post实现的时候可以选择同步或者异步实现.看一个请求是GET还是POST就看网址后面有没有携带请求体. GET与POST 区别  1.get请求 请求的网 ...

  2. Eclipse安装maven插件报错

    Eclipse安装maven插件,报错信息如下: Cannot complete the install because one or more required items could not be ...

  3. cat <<EOF用法

    转自:http://blog.csdn.net/apache0554/article/details/45508631 cat <<EOF和cat <<-EOF两个都是获取st ...

  4. iOS,文本输入,键盘相关

    1.UIKeyboard键盘相关知识点 2.点击空白区域隐藏键盘(UIKeyboard) 3.键盘(UIKeyboard)挡住输入框处理 4.自定义键盘(UIKeyboard) 5.监听键盘弹出或消失 ...

  5. WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while reading XML data错误

    WCF服务接口多,客户端在引用时出错!报WCF The maximum nametable character count quota (16384) has been exceeded while ...

  6. 解决img标签间距问题

    解决img标签间距问题 关于img标签间距问题:多个img之间有间距,包含img标签的div之间有间距. 代码如下: 1 <!doctype html> 2 <html lang=& ...

  7. PAT——乙级真题1002代码

  8. Python快速建站系列-Part.Two-结构化和布局

    |版权声明:本文为博主原创文章,未经博主允许不得转载. 首先明确我们要建一个什么样的站,作为教程(也算自己使用tornado的一个小总结),自然功能不能太多,但又满足一个普通网站需要的就行了. 目前想 ...

  9. -XX:-PrintClassHistogram 按下Ctrl+Break后,打印类的信息

    -XX:+PrintClassHistogram –按下Ctrl+Break后,打印类的信息: num     #instances         #bytes  class name ------ ...

  10. AJAX-----08jsonp跨域请求

    jsonp跨域请求其实我个人感觉并非传统上的ajax,因为传统的ajax几乎都是采用了xmlhttprequest这个对象来进行发送数据或者接收数据而已, 而jsop是通过双方约定成一个接口文件,然后 ...