美文网首页AndroidAndroid view我的Android之路
Android实现波浪效果 - WaveView

Android实现波浪效果 - WaveView

作者: gelitenight | 来源:发表于2015-09-14 14:26 被阅读14042次

    效果图

    先上效果图


    screenshot.gif

    实现

    WaveView的属性

    WaveView的属性
    • Wate Level(水位) - 波浪静止时水面距离底部的高度
    • Amplitude(振幅) - 波浪垂直振动时偏离水面的最大距离
    • Wave Length(波长) - 一个完整的波浪的水平长度
    • Wave Shift(偏移) - 波浪相对于初始位置的水平偏移

    实现思路

    设想我们有一个画好波形的图片,那么我们只需要用这张图片填充(X轴方向重复,Y轴方向延伸)整个View,然后水平移动图片,就可以得到波浪效果了。

    所以要做的事很简单:绘制一个波形图,填充到View里,移动波形图。

    1. 绘制初始波形

    private void createShader() {
        ...
    
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
    
        // Draw default waves into the bitmap
        // y=Asin(ωx+φ)+h
        float waveX1 = 0;
        final float wave2Shift = mDefaultWaveLength / 4;
        final float endX = getWidth();
        final float endY = getHeight();
    
        ...
    
        while (waveX1 < endX) {
            double wx = waveX1 * mDefaultAngularFrequency;
            int startY = (int) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx));
    
            // draw bottom wave with the alpha 40
            canvas.drawLine(waveX1, startY, waveX1, endY, wavePaint1);
            // draw top wave with the alpha 60
            float waveX2 = (waveX1 + wave2Shift) % endX;
            canvas.drawLine(waveX2, startY, waveX2, endY, wavePaint2);
    
            waveX1++;
        }
    
        // use the bitamp to create the shader
        mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
        mViewPaint.setShader(mWaveShader);
    }
    

    首先一个长宽恰等于WaveView的Bitmap:Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888)

    在Bitmap中使用默认的属性绘制出初始波形。初始波形的属性:Wate Level(水位)为WaveView高度的1/2;Amplitude(振幅)为WaveView高度的1/20;Wave Length(波长)等于WaveView的宽度。

    绘制好的初始波形是下面这个样子:

    初始波形

    代码第 9 ~ 27 行进行初始波形的绘制。波形由wave1和wave2两个波组成,wave2就是wave1向左偏移1/4的wave length,所以不需要重复计算。

    最后把这个Bitmap设置成为Paint的Shader。设置Shader相当于设定画笔的形状,使用设置了Shader的Paint绘制图形时,实际上是在使用Bitmap填充绘制的区域。X轴的填充方式为TileMode.REPEAT,即重复填充;Y轴的填充方式为TileMode.CLAMP,即使用边缘的色值延伸填充。

    2. 调整Bitmap的大小并填充到WaveView

    有了初始波形,当WaveView的属性改变时,只需要对初始波形进行相应的拉伸/压缩和位移就可以得到用户想要的波形。

    // sacle shader according to mWaveLengthRatio and mAmplitudeRatio
    // this decides the size(mWaveLengthRatio for width, mAmplitudeRatio for height) of waves
    mShaderMatrix.setScale(
            mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO,
            mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO,
            0,
            mDefaultWaterLevel);
    // translate shader according to mWaveShiftRatio and mWaterLevelRatio this decides the start position(mWaveShiftRatio for x, mWaterLevelRatio for 
    // this decides the start position(mWaveShiftRatio for x, mWaterLevelRatio for y) of waves
    mShaderMatrix.postTranslate(
            mWaveShiftRatio * getWidth(),
            (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
    
    // assign matrix to invalidate the shader
    mWaveShader.setLocalMatrix(mShaderMatrix);
    
    float radius = getWidth() / 2f
            - (mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth());
    canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint);
    

    代码 3 ~ 6 行对Shader进行拉伸/压缩,10 ~ 12 行对Shader进行水平/竖直平移。

    代码 17 ~ 19 行用Shader填充成想要的形状。

    3. 动画

    // horizontal animation.
    // wave waves infinitely.
    ObjectAnimator waveShiftAnim = ObjectAnimator.ofFloat(
            mWaveView, "waveShiftRatio", 0f, 1f);
    waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
    waveShiftAnim.setDuration(1000);
    waveShiftAnim.setInterpolator(new LinearInterpolator());
    animators.add(waveShiftAnim);
    
    // vertical animation.
    // water level increases from 0 to center of WaveView
    ObjectAnimator waterLevelAnim = ObjectAnimator.ofFloat(
            mWaveView, "waterLevelRatio", 0f, 0.5f);
    waterLevelAnim.setDuration(10000);
    waterLevelAnim.setInterpolator(new DecelerateInterpolator());
    animators.add(waterLevelAnim);
    
    // amplitude animation.
    // wave grows big then grows small, repeatedly
    ObjectAnimator amplitudeAnim = ObjectAnimator.ofFloat(
            mWaveView, "amplitudeRatio", 0f, 0.05f);
    amplitudeAnim.setRepeatCount(ValueAnimator.INFINITE);
    amplitudeAnim.setRepeatMode(ValueAnimator.REVERSE);
    amplitudeAnim.setDuration(5000);
    amplitudeAnim.setInterpolator(new LinearInterpolator());
    animators.add(amplitudeAnim);
    

    代码 3 ~ 8 行让波形一直向右移动,效果就是波形一直在波动。

    代码 12 ~ 16 行让水位从0逐渐涨到WaveView高度的一半。

    代码 20 ~ 26 行波浪的大小从大变小,再从小变大。


    源代码

    代码在github:WaveView


    打个广告

    美团平台及酒旅事业群招人啦,欢迎加入我们!
    我可以帮忙内推,简历请发到我邮箱gelitenight@gmail.com

    【美团网】高级Android开发工程师
    工作内容: 负责美团酒店、旅游产品 Android 客户端的设计、开发与改进。

    1. 3年以上工作经验,2年以上Android开发经验;
    2. 熟悉Android系统,熟悉Android软件的开发、测试、分发流程;
    3. 良好的编程风格,扎实的编程基础和数据结构算法基础;
    4. 熟悉移动网络的特性,对网络编程和常用网络协议有较深刻理解和经验;
    5. 有一定的架构设计能力,良好的编码能力,编写文档能力;
    6. 热爱互联网和新技术,具有极强的快速学习能力;
    7. 有以下特征优先考虑:
      • 有开源作品或技术博客(需原创技术文章);
      • 熟悉Socket编程。

    北京、上海、厦门、成都都有职位,更多职位请见职位列表


    本文遵循“署名-非商业性使用-相同方式共享”的创作共同协议,欢迎转载,转载时请注明作者和出处。
    作者: gelitenight
    出处: http://gelitenight.github.io/wave-view/

    相关文章

      网友评论

      • return_toLife:缩放大小之后出现锯齿怎么办呢?急需
        return_toLife:@无尽荒野 调整初始参数的值就可以改变原始bitmap的大小
        4269261ea721:@JJ_code 怎么画大?
        return_toLife:已经解决,将原始Bitmap的图画大一点可以避免放太大导致失真,感谢开源
      • a7faab8fc914:請問下setWaterLevelRatio 的值不管是多少都是顯示0.5 是什麽問題?
      • dd61ef7c40ca:大波浪可以!
      • 3aeed58e13cf:您好,我用了之后发现波浪是在圆形外面,就是整个控件里面,而不是在我想要的圆形里面,这个是在哪儿设置的啊?我要怎么改啊?谢谢
      • 我兜里有糖哟:Wate Level这个怎么不能改变呀
      • PM_陈叨叨:请问这个可以动态改变高度吗?就是根据后台返回的数据实时更改波浪我振幅高度
        gelitenight:可以啊,调用setAmplitudeRatio就行
      • bac89afd1f2a:请问这个可以动态改变高度吗?
        a7faab8fc914:@TonyEasy 我也是用了没效果
        TonyEasy:@gelitenight 我试着没有效果呢
        gelitenight:setWaterLevelRatio
      • 多思考少说话:ObjectAnimator amplitudeAnim = ObjectAnimator.ofFloat(
        mWaveView, "amplitudeRatio", 0.0001f, 0.3f);
        我把波动调整大一些后, 就跟平移一样,没有波浪效果了,请问我改怎么调整呢
      • cb9ceedb1def:楼主,在请教下,我现在想绘制只显示一条波浪线的效果,怎么在你那个原来基础上改动啊
        ,我把布局高度写很小,然后再形状那加了个drawLine结果就一条直线也不动。。。求指教
      • cb9ceedb1def:楼主,在请教下,我现在想绘制只显示一条波浪线的效果,怎么改动,我把布局高度写很小,然后再形状那加了个drawLine结果就一条直线也不动。。。求指教
        cb9ceedb1def:@lishiwei 没有troke这个只有 FILL,
        FILL_AND_STROKE,
        STROKE;
        lishiwei:paint 设置成 troke就好啦 Paint.setStyle(Style.STROKE)。
      • 喝咖啡的鱼儿:这个waveview在滑动的时候,没有人遇到view重叠的问题吗?如果有的话,有人有解决方案吗?
      • cb9ceedb1def:请教哈,我要实现出来就一直动,波浪不是从底部出来的。。。怎么做呢
        gelitenight:用法参见github代码里的demo
      • winnerliu:振幅大时 锯齿很明显额
      • fe91de07cf25:我只需要线 不需要下面那一大块怎么弄
      • Pasca:已经用上了~~谢谢
      • apkcore:还是这个比较省内存,感谢分享
        fe91de07cf25:@Trash 你知道怎么去掉下面的东西吗 就只要线条
      • 小_路子:谢谢大神无私分享,赞赞赞 :+1: :+1:
      • 缪婷ing:好棒的东西
      • lcodecore:展示的图是用什么画的😳
        gelitenight:@lcodecore 手机截屏
      • atomic_volatile:赞,给力
      • 痕迹Dev:之前的项目已经用上了!
        y0ngb1n:@痕迹BLANK 好的,谢谢
        gelitenight:@ybin1212 github的代码里面有demo。这一篇只是原理
        y0ngb1n:@痕迹BLANK 您好,我看了好多遍了,一直不知道该怎么用,新手,希望老司机出个教程,谢谢

      本文标题:Android实现波浪效果 - WaveView

      本文链接:https://www.haomeiwen.com/subject/jzxmcttx.html