1. 程式人生 > >Android自定義View——實現水波紋效果類似剩余流量球

Android自定義View——實現水波紋效果類似剩余流量球

string 三個點 pre ber block span 初始化 move 理解

最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧:

效果圖鎮樓

技術分享

一:先一步一步來分解一下實現的過程

  1. 需要繪制一個正弦曲線(sin)或者余弦曲線(cos)
  2. 通過水平平移曲線來的到像水波波動的效果
  3. 水平移動的同時還需要有水位上漲,也就是向上平移
  4. 裁剪畫布為圓形,在圓形區域繪制曲線
  5. 通過上面4步就可以實現了

二:現在就來實現第一步,繪制一個sin曲線;這裏畫了一張圖來幫助理解,在PhotoShop中我們繪制一個貝塞爾曲線可以清楚的看到它的控制點如圖:

技術分享 技術分享

???繪制貝塞爾曲線我們必須要知道三個點:起點、控制點、終點;有了這三個點我們就可以繪制一段簡單二階貝塞爾曲線。從圖中我們可以看出 起點 控制點p1 x1 這三個點繪制了一段曲線,也就是通過path.quadTo()函數添加一個曲線路徑。
???假設我們需要繪制一個周期的sin曲線,那麽我們就只需要知道起點、一個周期的寬度、振幅;就可以繪制一個sin曲線了。

三:下面就來看下代碼的實際操作了,這裏就直接省略掉一些畫筆初始化的操作了可以點擊這裏查看源碼

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    //獲取view的寬度
    width = getViewSize(800, widthMeasureSpec);
    //獲取view的高度
    height = getViewSize(400, heightMeasureSpec);
    //獲取起點坐標
    startPoint = new Point(0, height / 2);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

首先肯定是要獲取到畫布的大小才能確定好起點的坐標,有了起點坐標就可以開始繪制我們的曲線了

在ondraw()函數中進行曲線的繪制

/*sin曲線 1/4個周期的寬度*/
private int cycle = 200;
/*sin曲線振幅的高度*/
private int waveHeight = 200;

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    path.moveTo(startPoint.x, startPoint.y);
    int j = 1;
    //循環繪制正弦曲線 循環一次半個周期
    for (int i = 1; i <= 8; i++) {
        if (i % 2 == 0) {
        //波峰
            path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,
                    startPoint.x + (cycle * 2) * i, startPoint.y);
        } else {
        //波谷
            path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,
                    startPoint.x + (cycle * 2) * i, startPoint.y);
        }
        j += 2;
    }
    //繪制封閉的曲線
    path.lineTo(width, height);//右下角
    path.lineTo(startPoint.x, height);//左下角
    path.lineTo(startPoint.x, startPoint.y);//起點
    path.close();
    canvas.drawPath(path, paint);
}
  • 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

經過上面一系例操作一個水波紋效果就出來啦

技術分享

四:接下來就是水平移動這個曲線了為了移動起來更加好看,我們需要在屏幕外面開始繪制一個周期,如下:

//初始化的時候將起點移至屏幕外一個周期
startPoint = new Point(-cycle * 4, height / 2);

//繼續在ondraw()函數最後追加平移代碼

//判斷是不是平移完了一個周期
if (startPoint.x + 40 >= 0) {
    //滿了一個周期則恢復默認起點繼續平移
    startPoint.x = -cycle * 4;
}
//每次波形的平移量 40
startPoint.x += 40;
postInvalidateDelayed(150);
path.reset();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

只需要這樣就可以產生水波效果了,一起來看效果圖吧。

技術分享

五:接下來就是要將畫布變成圓形了(其實還是個矩形,只是繪畫區域在你所裁剪的區域),然後在裏面實現水波紋就哦的K了;完整的繪制代碼如下:

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //裁剪畫布為圓形
    Path circlePath = new Path();
    circlePath.addCircle(width / 2, height / 2, width / 2, Path.Direction.CW);
    canvas.clipPath(circlePath);
    canvas.drawPaint(circlePaint);
    canvas.drawCircle(width / 2, height / 2, width / 2, circlePaint);
    //以下操作都是在這個圓形畫布中操作
    //根據進度改變起點坐標的y值
    startPoint.y = (int) (height - (progress / 100.0 * height));
    //起點
    path.moveTo(startPoint.x, startPoint.y);
    int j = 1;
    //循環繪制正弦曲線 循環一次半個周期
    for (int i = 1; i <= 8; i++) {
        if (i % 2 == 0) {
            path.quadTo(startPoint.x + (cycle * j), startPoint.y + waveHeight,
                    startPoint.x + (cycle * 2) * i, startPoint.y);
        } else {
            path.quadTo(startPoint.x + (cycle * j), startPoint.y - waveHeight,
                    startPoint.x + (cycle * 2) * i, startPoint.y);
        }
        j += 2;
    }
    //繪制封閉的曲線
    path.lineTo(width, height);//右下角
    path.lineTo(startPoint.x, height);//左下角
    path.lineTo(startPoint.x, startPoint.y);//起點
    path.close();
    canvas.drawPath(path, paint);
    drawText(canvas, textPaint, progress + "%");
    //判斷是不是平移完了一個周期
    if (startPoint.x + 40 >= 0) {
        //滿了一個周期則恢復默認起點繼續平移
        startPoint.x = -cycle * 4;
    }
    //每次波形的平移量 40
    startPoint.x += 40;
    if (autoIncrement) {
        if (progress >= 100) {
            progress = 0;
        } else {
            progress++;
        }
    }
    postInvalidateDelayed(150);
    path.reset();
}

Android自定義View——實現水波紋效果類似剩余流量球