zoukankan      html  css  js  c++  java
  • Android 自定义波浪动画 --"让进度浪起来~"

    原文链接:

    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吧~ 感谢各位读者阅读。

  • 相关阅读:
    用EasyDarwin进行IPTV rtsp mpeg-ts smil流的转发和分发直播服务
    EasyDarwin添加自定义的服务模块EasyMyModule
    EasyDarwin添加自定义的服务模块EasyMyModule
    EasyDarwin Streaming Server对Task的调用方法
    EasyDarwin Streaming Server对Task的调用方法
    开源G711A/PCMA、G711U/PCMU、G726、PCM转码AAC项目EasyAACEncoder
    开源G711A/PCMA、G711U/PCMU、G726、PCM转码AAC项目EasyAACEncoder
    EasyDarwin EasyClient开源流媒体播放器,支持多窗口显示
    EasyDarwin EasyClient开源流媒体播放器,支持多窗口显示
    解决用EasyDarwin开源流媒体服务器做HLS直播时Flash Player卡住的问题
  • 原文地址:https://www.cnblogs.com/xgjblog/p/6134466.html
Copyright © 2011-2022 走看看