Android 自定义波浪动画--"让进度浪起来~"

waveview

《Android 自定义波浪动画之"让进度浪起来~"》
转载请注明来自 傻小孩b_移动开发//www.greatytc.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吧~ 感谢各位读者阅读。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 版权声明:本文为博主原创文章,未经博主允许不得转载。系列教程:Android开发之从零开始系列源码:github....
    Anlia阅读 9,371评论 11 83
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,520评论 25 707
  • 世界上这么多人 能遇见就很难得❤能相识就很不错 有着美好的过去就应珍惜 聪明的人知道一段无果的爱情 就开始新的生活...
    GJSJDBI阅读 247评论 0 1
  • 近期目标是财富增长!通过学习智慧和实践智慧并用成功的案例传播智慧,让身边更多的人接受智慧并学习智慧。让世界因智慧而...
    belivePossible阅读 210评论 0 0