天天看點

Android貝塞爾曲線水紋波動效果、車輛監控效果

最近因工作需要做了一個Android基本開發的教育訓練,這裡把其中Android貝塞爾曲線應用的章節部分拿出來分享。先上圖看效果,包括水紋波動以及利用水紋波動實作車輛監控兩種效果圖,本文主要講解怎麼利用貝塞爾二次曲線實作水紋波動效果。

Android貝塞爾曲線水紋波動效果、車輛監控效果

1、貝塞爾曲線簡介

貝塞爾曲線的得名是由于 1962 年就職于雷諾的法國工程師Pierre Bézier的廣泛宣傳。他使用這種隻需要很少的控制點就能夠生成複雜平滑曲線的方法,來輔助汽車車體的工業設計。正是因為控制簡便卻具有極強的描述能力,貝塞爾曲線在工業設計領域迅速得到了廣泛的應用。

Android貝塞爾曲線水紋波動效果、車輛監控效果

如何用de Casteljau算法繪制一條貝塞爾曲線,請參考網上其它文章。貝塞爾曲線是用一系列點來控制曲線狀态的,可以将這些點簡單分為兩類:資料點(确定曲線的起始和結束位置)、控制點(确定曲線的彎曲程度)。通過調整控制點貝塞爾曲線形狀會發生變化。

2、Android貝塞爾曲線常用函數

Android中Path類中已經有封裝好了的關于貝塞爾曲線的函數。

//二階貝賽爾 
public void quadTo(float x1, float y1, float x2, float y2) 
public void rQuadTo(float dx1, float dy1, float dx2, float dy2) 
//三階貝賽爾 
public void cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 
public void rCubicTo(float x1, float y1, float x2, float y2,float x3, float y3)
           

2.1、cubicTo()

檢視quadTo()函數源碼看到其參數中(x1,y1)是控制點坐标,(x2,y2)是終點坐标。整條線的起始點是通過Path.moveTo(x,y)來指定的,而如果我們連續調用quadTo(),前一個quadTo()的終點,就是下一個quadTo()函數的起點。如果初始沒有調用Path.moveTo(x,y)來指定起始點,則預設以控件左上角(0,0)為起始點。

2.2、rQuadTo()

rQuadTo()函數參數與quadTo()不同,具體說明如下:

dx1:控制點X坐标,表示相對上一個終點X坐标的位移坐标,可為負值,正值表示相加,負值表示相減;

dy1:控制點Y坐标,相對上一個終點Y坐标的位移坐标。同樣可為負值,正值表示相加,負值表示相減;

dx2:終點X坐标,同樣是一個相對坐标,相對上一個終點X坐标的位移值,可為負值,正值表示相加,負值表示相減;

dy2:終點Y坐标,同樣是一個相對,相對上一個終點Y坐标的位移值。可為負值,正值表示相加,負值表示相減;

假如我們上一個終點坐标是(300,400),那麼利用rQuadTo(100,-100,200,100); 得到的控制點坐标是(300+100,400-100)即(500,300) 同樣,得到的終點坐标是(300+200,400+100)即(500,500),這個方法使用上和quadTo()方法沒什麼差別。

2.3、cubicTo()

這是Android的三階貝塞爾曲線方法,檢視源碼可以看到參數(x1,y1)是第一個控制點坐标,(x2,y2)是第二個控制點坐标,(x3,y3)是終點坐标。同樣整條線的起始點是通過Path.moveTo(x,y)來指定的,而如果我們連續調用cubicTo(),前一個cubicTo()的終點,就是下一個cubicTo()函數的起點;如果初始沒有調用Path.moveTo(x,y)來指定起始點,則預設以控件左上角(0,0)為起始點。

2.4、rCubicTo()方法源碼

參數說明同rQuadTo。

3、水紋波動效果

為了實作連續的波動效果,我們需要在螢幕内和螢幕外各畫一個完整波紋,然後不間斷進行水準方向平移動畫。

Android貝塞爾曲線水紋波動效果、車輛監控效果

首先是采用貝塞爾二次曲線畫出兩個完整波紋,即對上圖中AB、BC、CD、DE曲線段利用貝塞爾二次曲線rQuadTo畫出。核心代碼是drawWave()這個方法,其中mWaveDx是計算出的螢幕寬度,mWaveHeight是貝塞爾曲線控制點高度,dx是動畫每次的偏移量。

private void drawWave(Canvas canvas) {
    Path path = new Path();
    path.reset();
    path.moveTo(-mWaveDx + dx, mHeight / 2);
    for (int i = -mWaveDx; i < getWidth() + mWaveDx; i += mWaveDx) {
        path.rQuadTo(mWaveDx / 4, -mWaveHeight, mWaveDx / 2, 0);
        path.rQuadTo(mWaveDx / 4, mWaveHeight, mWaveDx / 2, 0);
    }
    path.lineTo(mWidth, mHeight);
    path.lineTo(0, mHeight);
    //path.close() 繪制封閉的區域
    path.close();
    canvas.drawPath(path, mPaint);
}
           

完整的波紋已經畫出,下面就是實作波動效果。這裡借助ValueAnimator對貝塞爾曲線不斷繪制,并生成一個偏移量dx,使得每次繪制的起點平滑右移,進而實作水紋波動效果。

ValueAnimator屬性動畫的運作機制是通過不斷地對值進行操作來實作的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的内部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們隻需要将初始值和結束值提供給ValueAnimator,并且告訴它動畫所需運作的時長,那麼ValueAnimator就會自動完成從初始值平滑地過渡到結束值這樣的效果。

public void waveAnimation() {
        // valueAnimator對象,初始值為0,結束值為mWaveDx,mWaveDx為整個螢幕寬度
        ValueAnimator valueAnimator = ValueAnimator.ofInt(0, mWaveDx);
        // 設定屬性動畫時長
        valueAnimator.setDuration(2000);
        // 無線重複動畫
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //水準方向的偏移量,值的區間為0~mWaveDx,根據偏移量重繪貝塞爾曲線
                dx = (int)animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimator.start();
    }
           

最終效果圖就是文章開頭供圖,隻給出了靜态截圖,實際示範動态效果可以下載下傳源碼運作,下載下傳位址https://download.csdn.net/download/wangpf2011/10986376。