1. 程式人生 > >Android貝塞爾曲線-水波篇

Android貝塞爾曲線-水波篇

在做自定義view時,很多時候會用到貝塞爾曲線這個東西去實現一些效果,像以前寫的那個仿直播點贊動畫的實現就是用到了貝塞爾曲線,這次說的水波也會用到貝塞爾曲線這個東西。

Android貝塞爾曲線api

首先看下貝塞爾曲線公式:

一階

這裡寫圖片描述

二階

這裡寫圖片描述

其中p0是起點,p1是控制點,p2是終點

三階

這裡寫圖片描述

其中p0是起點,p1,p2是控制點,p3是終點

Android做好了相應的api,分別如下:

二階:

quadTo(float x1, float y1, float x2, float y2)
rQuadTo(float dx1, float dy1, float dx2, float dy2)

三階:

cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

因為這裡主要用到了二階盃賽曲線,所以主要講一下這個

api解釋及運用

quadTo(float x1, float y1, float x2, float y2)

quadTo是引數解釋:
x1:控制點x座標
y1:在控制點y座標
x2:終點x座標
y2:終點y座標

先看段例子:

 pathRed.moveTo
(getWidth()/2-100,getHeight()/2); pathRed.quadTo(getWidth()/2-50,getHeight()/2-50,getWidth()/2,getHeight()/2); pathRed.quadTo(getWidth()/2+50,getHeight()/2+50,getWidth()/2+100,getHeight()/2); canvas.drawPath(pathRed,paintRed);

得到的圖形如下

這裡寫圖片描述

這裡解釋一點:當連續呼叫quadTo的時候上一個quadTo的終點即為寫下一個quadTo的起點

rQuadTo(float dx1, float dy1, float dx2, float dy2)

dx1:控制點相對起點的x位移
dy1:控制點相對起點的y位移
dx2:終點相對起點的x位移
dy2:終點相對起點的y位移

把上面那段程式碼改改即為如下所示:

 pathRed.moveTo(getWidth()/2-100,getHeight()/2);
 pathRed.rQuadTo(50,-50,100,0);
 pathRed.rQuadTo(50,50,100,0);

圖就不上了,也是同樣的效果

水波實現

首先先做出來一個靜態的水波,如下圖所示:

這裡寫圖片描述

再看下程式碼

 public void drawMyPath(int wavehigh,Path path){
        path.reset();
        path.moveTo(-waveRed,high/2);
        for (int i = -waveRed; i < getWidth()+waveRed; i+=waveRed) {
            path.rQuadTo(waveRed/4,-wavehigh,waveRed/2,0);
            path.rQuadTo(waveRed/4,wavehigh,waveRed/2,0);

        }
        path.lineTo(getWidth(),getHeight());
        path.lineTo(0,getHeight());
        path.close();
    }

wavehigh是定義的水波高度,waveRed是指水波長度,我們要做的就是在螢幕左右各預留一個波長以便後續的移動。

接下來要做的就是怎麼能讓波形移動了,因為已經預留了兩邊的波長所以只要讓path的起點慢慢移動一個波長就形成了視覺上的水波效果

程式碼如下:

 public void drawMyPath(int wavehigh,Path path,int y){
        path.reset();
        path.moveTo(-waveRed+y+dx,high/2);
        for (int i = -waveRed; i < getWidth()+waveRed; i+=waveRed) {
            path.rQuadTo(waveRed/4,-wavehigh,waveRed/2,0);
            path.rQuadTo(waveRed/4,wavehigh,waveRed/2,0);

        }
        path.lineTo(getWidth(),getHeight());
        path.lineTo(0,getHeight());
        path.close();
    }
 public void startAnimation(){
        ValueAnimator animator=ValueAnimator.ofInt(0,waveRed);
        animator.setDuration(2000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                dx= (int) valueAnimator.getAnimatedValue();
                if (dx == waveRed) {
                    dx=0;

                }

                postInvalidate();
            }
        });
        animator.start();



    }

然後在外部呼叫一下讓動畫開始執行就行,看下具體效果:

這裡寫圖片描述

那這時我想做多條水波怎麼辦呢,還記得前面drawMyPath方法裡的y引數嗎,它就是控制起點位置,然後再改變一下水波高度就行了

這裡寫圖片描述

我是隨便設定的,可能不太明顯,能看出來就行

好了差不多說完了,下一篇說下怎麼做出圓形水波view