Android自定義View——實現水波紋效果類似剩余流量球
阿新 • • 發佈:2017-09-06
string 三個點 pre ber block span 初始化 move 理解
最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧:
效果圖鎮樓
一:先一步一步來分解一下實現的過程
- 需要繪制一個正弦曲線(sin)或者余弦曲線(cos)
- 通過水平平移曲線來的到像水波波動的效果
- 水平移動的同時還需要有水位上漲,也就是向上平移
- 裁剪畫布為圓形,在圓形區域繪制曲線
- 通過上面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——實現水波紋效果類似剩余流量球