android實現貝塞爾曲線之波浪效果

本文實例為大傢分享瞭android實現貝塞爾曲線之波浪效果的具體代碼,供大傢參考,具體內容如下

1 前言

為瞭給我以前的博客填坑,這章講解貝塞爾曲線的幾個常用的應用:

1.波浪效果
2.qq聊天列表上的沾粘體效果
3.翻書頁效果
4.彈性球效果

大傢如果把這些看懂並掌握,以後做和貝塞爾曲線相關的效果應該都能信手拈來!

2 波浪效果

原理分析:

其實這個效果應用瞭2個階的貝塞爾曲線來完成的,先看一下原理分析圖:

有上面的圖可以看出:在屏幕的左面畫出瞭1.5個波長,在屏幕中畫出1個波長,然後讓它循環的向右移動,這個就會出現波浪效果,這裡有幾點需要註意:

1.為什麼是1.5個波長而不是1個波長呢?

理論上1個波長就夠瞭,但是實際運行出來的效果會出現不協調,所以經過調試,我又加瞭0.5個波長

2.那條綠線是幹什麼用的?

在波浪線以下的所有空間都要填充成一個顏色,所以path必須是封閉的區間,隻有這個才能填充。代碼中我會具體的解釋

我們在編碼的時候隻需要計算最左面半個波長的坐標,其他的用for循環搞定。

好瞭我們看一下代碼:

public class WaveView extends View {
    private int  width = 0;
    private int height = 0;
    private int baseLine = 0;// 基線,用於控制水位上漲的,這裡是寫死瞭沒動,你可以不斷的設置改變。
    private Paint mPaint;
    private int waveHeight = 100;// 波浪的最高度
    private int waveWidth  ;//波長
    private float offset =0f;//偏移量
    public WaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    /**
     * 不斷的更新偏移量,並且循環。
     */
    private void updateXControl(){
        //設置一個波長的偏移
        ValueAnimator mAnimator = ValueAnimator.ofFloat(0,waveWidth);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float animatorValue = (float)animation.getAnimatedValue() ;
                offset = animatorValue;//不斷的設置偏移量,並重畫
                postInvalidate();
            }
        });
        mAnimator.setDuration(1000);
        mAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mAnimator.start();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(getPath(),mPaint);
    }
    //初始化paint,沒什麼可說的。
    private void initView(){
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        width = getMeasuredWidth();//獲取屏幕寬度
        height = getMeasuredHeight();//獲取屏幕高度
        waveWidth = width;
        baseLine = height/2;
        updateXControl();
    }

    /**
     * 核心代碼,計算path
     * @return
     */
    private Path  getPath(){
        int itemWidth = waveWidth/2;//半個波長
        Path mPath = new Path();
        mPath.moveTo(-itemWidth * 3, baseLine);//起始坐標
        //核心的代碼就是這裡
        for (int i = -3; i < 2; i++) {
            int startX = i * itemWidth;
            mPath.quadTo(
                    startX + itemWidth/2 + offset,//控制點的X,(起始點X + itemWidth/2 + offset)
                    getWaveHeigh( i ),//控制點的Y
                    startX + itemWidth + offset,//結束點的X
                    baseLine//結束點的Y
            );//隻需要處理完半個波長,剩下的有for循環自已就添加瞭。
        }
        //下面這三句話很重要,它是形成瞭一封閉區間,讓曲線以下的面積填充一種顏色,大傢可以把這3句話註釋瞭看看效果。
        mPath.lineTo(width,height);
        mPath.lineTo(0,height);
        mPath.close();
        return  mPath;
    }
    //奇數峰值是正的,偶數峰值是負數
    private int getWaveHeigh(int num){
        if(num % 2 == 0){
            return baseLine + waveHeight;
        }
        return baseLine - waveHeight;
    }
}

核心的代碼在 getPath()方法中,其實這個坐標是有規律的:

先找到最左面的半個波長,設置貝塞爾曲線坐標,
然後用for循環,不斷的設置,

這個規律大傢體會,我這裡簡單提一下。

3 qq聊天列表上的沾粘體效果

先看一個效果圖:

這個做起來小有點復雜。具體思路如下:

1.畫兩個圓,一個黏連小球固定在一個點上,一個氣泡小球跟隨手指的滑動改變坐標。隨著兩個圓間距越來越大,黏連小球半徑越來越小。
2.當間距小於一定值,松開手指氣泡小球會恢復原來位置;
3.當間距超過一定值之後,黏連小球消失,氣泡小球繼續跟隨手指移動,此時手指松開,氣泡小球消失~

結尾

本來想把上面的全部弄在一篇博客呢,現在看來不太可能,一篇一篇的來吧。核心就是貝塞爾曲線的應用,大傢如何理解瞭貝塞爾曲線,這些都不難。

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: