自定義view,貝塞爾曲線實現水波紋效果的動畫
阿新 • • 發佈:2018-12-17
作為一名碼農,除了用基本的姿勢去搬磚,還應該get一些炫酷的技能,用高逼格的姿態去搬磚。而貝塞爾曲線無疑是炫酷技能之一。
簡介:
Bézier curve(貝塞爾曲線)是應用於二維圖形應用程式的數學曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。 1962年,法國數學家Pierre Bézier第一個研究了這種向量繪製曲線的方法,並給出了詳細的計算公式,因此按照這樣的公式繪製出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線。
貝塞爾曲線作用十分廣泛,比如下面的幾個場景:
- QQ小紅點拖拽效果
- 一些炫酷的下拉重新整理控制元件
- 閱讀軟體的翻書效果
- 一些平滑的折線圖的製作
- 炫酷的動畫效果
貝塞爾曲線的原理:
-
一階貝塞爾曲線(線段): 公式: 原理:由 P0 至 P1 的連續點, 描述的一條線段
-
二階貝塞爾曲線(拋物線): 公式: 原理: 由 P0 至 P1 的連續點 Q0,描述一條線段。 由 P1 至 P2 的連續點 Q1,描述一條線段。 由 Q0 至 Q1 的連續點 B(t),描述一條二次貝塞爾曲線。 可以理解成:P1-P0為曲線在P0處的切線。
-
三階貝塞爾曲線 公式:
接下來用貝塞爾曲線實現一個水波紋動畫效果的自定義view
- ui效果:
- 程式碼:
public class WaveView extends View { private Paint mPaint; private Path mPath; private int viewWidth, viewHeight; //控制元件的寬和高 private float commandX, commandY; //控制點的座標 private float waterHeight; //水位高度 private boolean isInc;// 判斷控制點是該右移還是左移 public WaveView(Context context, AttributeSet attrs) { super(context, attrs); init(); } /** * 初始化畫筆 路徑 */ private void init() { //畫筆 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.parseColor("#AFDEE4")); //路徑 mPath = new Path(); } /** * 獲取控制元件的寬和高 */ @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); viewWidth = w; viewHeight = h; // 控制點 開始時的Y座標 commandY = 7 / 8f * viewHeight; //終點一開始的Y座標 ,也就是水位水平高度 , 紅色輔助線 waterHeight = 15 / 16F * viewHeight; } /** * 繪製 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPath.moveTo(-1 / 4F * viewWidth, waterHeight);// 起始點位置 //繪製水波浪 mPath.quadTo(commandX, commandY, viewWidth + 1 / 4F * viewWidth, waterHeight);//二階貝塞爾曲線 //繪製波浪下方閉合區域 mPath.lineTo(viewWidth + 1 / 4F * viewWidth, viewHeight);//一階貝塞爾曲線 mPath.lineTo(-1 / 4F * viewWidth, viewHeight);//一階貝塞爾曲線 mPath.close(); //繪製路徑 canvas.drawPath(mPath, mPaint); //產生波浪左右湧動的感覺 if (commandX >= viewWidth + 1 / 4F * viewWidth) {//控制點座標大於等於終點座標改標識 isInc = false; } else if (commandX <= -1 / 4F * viewWidth) {//控制點座標小於等於起點座標改標識 isInc = true; } commandX = isInc ? commandX + 20 : commandX - 20; //水位不斷加高 當距離控制元件頂端還有1/8的高度時,不再上升 if (commandY >= 1 / 8f * viewHeight) { commandY -= 2; waterHeight -= 2; } //路徑重置 mPath.reset(); // 重繪 invalidate(); } /** * 測量 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int wSpecMode = MeasureSpec.getMode(widthMeasureSpec); int wSpecSize = MeasureSpec.getSize(widthMeasureSpec); int hSpecMode = MeasureSpec.getMode(heightMeasureSpec); int hSpecSize = MeasureSpec.getSize(heightMeasureSpec); if (wSpecMode == MeasureSpec.AT_MOST && hSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(300, 300); } else if (wSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(300, hSpecSize); } else if (hSpecMode == MeasureSpec.AT_MOST) { setMeasuredDimension(wSpecSize, 300); } } }