波浪控件自定义

1.首先我们需要做的就是一个波浪形的组件,并且需要不停的流动

怎么样才能有一个波浪形的效果,我们在android绘图的api里面没有提供绘制一个正弦或者余弦的方法,但是在Path里面提供了绘制贝塞尔曲线的方法quadTo();利用这个方法我们可以绘制出一个波浪形的曲线出来.


public class WaveView extends View {
    private int mWidth ,mHeight ;
    private Paint paint_1  ;
    private Path mPath_1 // 路径
    private int movePath  =0 ,movePath2 = 0;
    public WaveView(Context context) {
        super(context);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context ,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint_1 = new Paint() ;
        paint_1.setStrokeWidth(10);
        paint_1.setColor(Color.argb(70, 255, 255, 255));
        paint_1.setAntiAlias(true);
        paint_1.setStyle(Style.STROKE);
        mPath_1 = new Path() ;

    }

    @Override
    protected void onDraw(Canvas canvas) {

        mPath_1.moveTo(0, mHeight/2);
        mPath_1.quadTo(mWidth/4, mHeight/2-80, mWidth/2, mHeight/2);
        mPath_1.quadTo(mWidth*3/4, mHeight/2+80, mWidth, mHeight/2);
        canvas.drawPath(mPath_1, paint_1);




    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mWidth = w ;
        this.mHeight = h ;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

效果图:这里写图片描述

2.已经基本掌握了贝塞尔曲线的方法以后我们就可以考虑怎么样能够让波浪流动起来,这才是重点。

考虑流动以及后面曲线怎样才能比较好画的,我们将曲线延长一倍,可以这样来考虑,图丑莫怪! 
这里写图片描述,将移动的位置设置成movePath,当movePath不断的增大的时候,波浪也就随之产生了。当movePath移动到大于当前的宽度的时候,我们将movePath清零,回到原点,继续开始,就产生了不断变化的波浪,其实我们只有两段波浪的移动在不停的重复变化。

package com.evan.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

public class WaveView extends View {
    private int mWidth ,mHeight ;
    private Paint paint_1  ;
    private Path mPath_1 ;// 路径
    private int movePath  =0 ,movePath2 = 0;
    public WaveView(Context context) {
        super(context);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context ,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        paint_1 = new Paint() ;
        paint_1.setStrokeWidth(10);
        paint_1.setColor(Color.argb(70, 255, 255, 255));
        paint_1.setAntiAlias(true);
        paint_1.setStyle(Style.FILL);
        mPath_1 = new Path() ;
    }

    @Override
    protected void onDraw(Canvas canvas) {



        mPath_1.reset();
        //不断增大movePath的距离
        movePath=movePath+5;
        //档movePath大于当前屏幕大小时候回到原点
        if(movePath>=mWidth) {
            movePath=movePath-mWidth;
        }
        //将当前的起点移动到屏幕外的-mWidth距离
        mPath_1.moveTo(-mWidth +movePath, mHeight/2);
        /**
        *在对应的位置使用贝塞尔曲线,生成波浪效果
        */
        mPath_1.quadTo(-mWidth+mWidth/4+movePath, mHeight/2 -40, -mWidth+mWidth/2+movePath, mHeight/2);
        mPath_1.quadTo(-mWidth+mWidth*3/4+movePath, mHeight/2+40, 0 + movePath, mHeight/2);
        mPath_1.quadTo(mWidth/4+movePath,mHeight/2 -40, mWidth/2+movePath, mHeight/2);
        mPath_1.quadTo(mWidth*3/4+movePath, mHeight/2+40, mWidth+movePath, mHeight/2);
        mPath_1.lineTo(mWidth+movePath, mHeight);
        mPath_1.lineTo(-mWidth+movePath, mHeight);
        mPath_1.close() ;
        //绘制路径
        canvas.drawPath(mPath_1, paint_1);
        invalidate();

    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mWidth = w ;
        this.mHeight = h ;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

效果图这里写图片描述

3.添加另外一个向左移动的波浪,原理一样。代码略,在下面可以看到,贴个效果图就行了。

这里写图片描述 
(虚拟机上面这刷新速度也是醉了!!)

4.在波浪上面添加文字。

使用的方法。。。drawTextOnPath();据说此方法需要关闭硬件加速,在此之前,我弄死都画不出来,网上一搜,所噶。一种方法是在mainfest文件里卖弄添加一句关闭硬件加速的代码,另一种是在view初始化的时候加一句这个就行了: 
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null); 
先看一下drawTextOnPath(text, path, hOffset, vOffset, paint);的隔各个参数。 
text 显示文字内容 
path 显示文字的路径 文字会沿着改路径显示出来(当然,我们显示的路径就是我们绘制波浪时候的路径) 
hOffset 从起点开始计算到你需要绘制的文字的距离 0的时候为起点 
vOffset 路径的上下距离 +为上 -为下 
paint 绘制文字时候的画笔 
OK,代码如下

package com.evan.view;


public class WaveView extends View {
    private int mWidth ,mHeight ;
    private TextPaint tvPaint;
    private Paint paint_1 ,paint_2 ;
    private Path mPath_1 , mPath_2;// 2条路径
    private int movePath  =0 ,movePath2 = 0;//两条波浪的移动距离
    public WaveView(Context context) {
        super(context);
    }

    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context ,attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        paint_1 = new Paint() ;
        paint_2 = new Paint() ;
        paint_1.setStrokeWidth(10);
        tvPaint = new TextPaint() ;
        tvPaint.setTextSize(60);
        tvPaint.setTextAlign(Align.LEFT);
        tvPaint.setColor(Color.WHITE);
        tvPaint.setAntiAlias(true);
        //两条路径的颜色不一样,能区分出明暗
        paint_1.setColor(Color.argb(70, 255, 255, 255));
        paint_2.setColor(Color.argb(50, 255, 255, 255));
        paint_1.setAntiAlias(true);
        paint_2.setAntiAlias(true);
        paint_1.setStyle(Style.FILL);
        paint_2.setStyle(Style.FILL);
        mPath_1 = new Path() ;
        mPath_2 = new Path() ;
    }

    @Override
    protected void onDraw(Canvas canvas) {

        //每次刷新前需要reset路径
        mPath_1.reset();
        mPath_2.reset();
        //两条波浪的移动速度让他不一样,避免动作过于重复
        movePath=movePath+5;
        movePath2 = movePath2+4;        

        if(movePath>=mWidth) {
            movePath=movePath-mWidth;
        }
        if (movePath2>=mWidth) {
            movePath2 = movePath2-mWidth;
        }
        //第一条波浪
        mPath_1.moveTo(-mWidth +movePath, mHeight/2);
        mPath_1.quadTo(-mWidth+mWidth/4+movePath, mHeight/2 -40, -mWidth+mWidth/2+movePath, mHeight/2);
        mPath_1.quadTo(-mWidth+mWidth*3/4+movePath, mHeight/2+40, 0 + movePath, mHeight/2);
        mPath_1.quadTo(mWidth/4+movePath,mHeight/2 -40, mWidth/2+movePath, mHeight/2);
        mPath_1.quadTo(mWidth*3/4+movePath, mHeight/2+40, mWidth+movePath, mHeight/2);
        mPath_1.lineTo(mWidth+movePath, mHeight);
        mPath_1.lineTo(-mWidth+movePath, mHeight);
        mPath_1.close() ;
        //第二条波浪
        mPath_2.moveTo(mWidth+mWidth - movePath2, mHeight/2);
        mPath_2.quadTo(2*mWidth - movePath2 - mWidth/4, mHeight/2-40, 2*mWidth-movePath2-mWidth/2, mHeight/2);
        mPath_2.quadTo(2*mWidth - mWidth*3/4 - movePath2, mHeight/2+40, mWidth-movePath2, mHeight/2);
        mPath_2.quadTo(mWidth*3/4-movePath2, mHeight/2-40, mWidth/2-movePath2, mHeight/2);
        mPath_2.quadTo(mWidth/4-movePath2, mHeight/2+40, -movePath2, mHeight/2);
        mPath_2.lineTo(0, mHeight);
        mPath_2.lineTo(mWidth, mHeight);
        mPath_2.close();
            /**
         * 此处绘制文字
         * 由于我们多画了一倍的长度,所以我们在计算hOffset的时候需要加上一倍mWidth
         * 然后再根据movePath随时的计算位置
         */
        canvas.drawTextOnPath("26%", mPath_1,mWidth*3/2-movePath-tvPaint.measureText("26%")/2, -5, tvPaint);
        canvas.drawPath(mPath_1, paint_1);
        canvas.drawPath(mPath_2, paint_2);

        invalidate();

    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.mWidth = w ;
        this.mHeight = h ;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

效果图(太渣,真机上面运行效果更好): 
这里写图片描述

It’s over。需要代码的话后面在放出来。


猜你喜欢

转载自blog.csdn.net/qq_34500646/article/details/80069667