原文鏈接:
http://blog.csdn.net/sangxiaonian/article/details/51984013
http://blog.csdn.net/sangxiaonian/article/details/51984584
http://blog.csdn.net/sangxiaonian/article/details/51985405
其他參考鏈接:
https://www.jianshu.com/p/55c721887568
作為一個有只志向的碼農,除了知道一些基本的知識夠自己努力搬磚以外,還應該get一些更炫酷的技能,用更優雅的姿勢進行搬磚;想要實現一些十分炫酷的效果,貝塞爾曲線就必須進行一些研究了;
最近一段時間,我對貝塞爾曲線進行了部分的研究,因此就打算寫貝塞爾曲線系列的文章來記錄自己的研究;
規矩我都懂 !
我明白,必須先上圖,要不然大家都沒興趣看下去
先看比較簡單的,貝塞爾曲線的一階和二階的應用
看到二階的貝塞爾曲線有沒有感覺很眼熟,沒錯,360的下火箭彈射時候的小彈弓,還有滑動控件的陰影提示;以前的時候很多小伙伴跟我說這要計算多少數據啊,完全沒辦法實現啊,現在有了貝塞爾曲線,可以很簡單的實現這一個功能;
不過完全不能這樣滿足啊,接下來還有更復雜一些的曲線
沒錯,這個就是三階的使用,有沒有感覺路線更加復雜,不過還好,使用貝塞爾去玩完全可以輕松實現;對了,還有一個心在沿着曲線移動,看到這里,小伙伴們肯定會想到滿屏幕的心在飛的場景,放心,這個我也實現了,在接下來的文章里,我會一一進行講解;
圖片看完了,現在簡單了解貝塞爾曲線
Bézier curve(貝塞爾曲線)是應用於二維圖形應用程序的數學曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調整控制點,貝塞爾曲線的形狀會發生變化。 1962年,法國數學家Pierre Bézier第一個研究了這種矢量繪制曲線的方法,並給出了詳細的計算公式,因此按照這樣的公式繪制出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線。
以下公式中:B(t)為t時間下 點的坐標;
P0為起點,Pn為終點,Pi為控制點
一階貝塞爾曲線(線段):
意義:由 P0 至 P1 的連續點, 描述的一條線段
二階貝塞爾曲線(拋物線):
原理:由 P0 至 P1 的連續點 Q0,描述一條線段。
由 P1 至 P2 的連續點 Q1,描述一條線段。
由 Q0 至 Q1 的連續點 B(t),描述一條二次貝塞爾曲線。
經驗:P1-P0為曲線在P0處的切線。
三階貝塞爾曲線:
通用公式:
利用貝塞爾曲線的這些特性,我們可以畫出很多炫酷的曲線,所以貝塞爾曲線還是值得我們去研究學習的;
但是這些完全記不住啊!!!
沒關系,可以很負責的說,我也是!!!!!
上面的曲線完全是來自http://blog.csdn.net/tianhai110/article/details/2203572
所以,如果你的數學和我一樣是體育老師教的,就忘記這些吧,跟我一起看看android中是實現一條貝塞爾曲線的,android已經幫我們實現好了,剩下的就需要我們進行簡單使用,具體的使用,就看下一篇中講解
最后附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上一篇中我簡單的介(粘)紹(貼)了一下貝塞爾曲線(Bezier)曲線的原理和公式,但是作為數學界排的上名號的渣渣,我只能默默的溜過;
不過還好,android幫我們實現好了這個貝塞爾曲線的使用;
Path
這個類中封裝了要使用貝塞爾曲線(Bezier)的簡單方法;使用起來也很簡單,總的來說也只有三步
- 初始化Path
mPath = new Path();
- path移動到起點
mPath.moveTo(startX, startY / 3);
- 確定直線的終點
mPath.lineTo(endX, endY / 3);
- 調用canvas繪制貝塞爾曲線
canvas.drawPath(mPath, mPaint);
好了,到這里一階的一條直線就完成了;
但是這個完全沒任何卵用啊,就一條直線有木有!!
但是,我們可以一直畫下去,就像這樣:
path.moveTo(touchX + getWidth() / 20, touchY - getHeight() / 10); path.lineTo(touchX + getWidth() / 20, touchY); path.lineTo(touchX - getWidth() / 20, touchY); path.lineTo(touchX - getWidth() / 20, touchY - getHeight() / 10); path.lineTo(touchX, touchY - getHeight() / 7); path.lineTo(touchX + getWidth() / 20, touchY - getHeight() / 10 + 2);
這段代碼繪制完成之后就是一個隨着手指一動的小火箭了
丑爆了有木有,不過還好,如果是大神的話應該可以繪制成一個比較好一些的了吧,主要還是原理,相對於自己直接畫直線,已經大大簡化了;
二階曲線
二階曲線在安卓中的定義也是很簡單的,就是調用quadTo方法,
mPath.moveTo(startX, startY); mPath.quadTo(touchX, touchY, endX, endY); canvas.drawPath(mPath, mPaint);

不管是幾階的,都是要先moveTo到起點;
三階曲線 ##
mPath.moveTo(pointFStart.x, pointFStart.y); mPath.cubicTo(pointFFirst.x, pointFFirst.y, pointFSecond.x, pointFSecond.y, pointFEnd.x, pointFEnd.y); canvas.drawPath(mPath, mPaint);
途中從下倒上,四個點依次是pointFStart,pointFFirst,pointFSecond,pointFSecond;根本沒什么難度,非常簡單,可以直接使用,上篇提到的”心”的移動就是按照這個軌跡進行移動,所以看起來十分順滑,效果也不錯;
貝塞爾曲線的繪制本身並沒有什么難度,這些都是很基礎的一些東西,但是卻能實現一些很炫酷的效果,比如qq上的粘性控件的效果等,這些都可以實現;
好了,簡單的使用就介紹到這里了,下一篇我會利用貝塞爾曲線實現一些炫酷的效果
最后附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
這一篇文章會完整的介紹如何通過貝塞爾曲線實現愛心點贊的效果,如果實在看不懂,可以看第一篇貝塞爾曲線的簡介,還有第二篇安卓中的簡單使用;
好了,終於到了放大招的時候了,真實憋了很久了
先做一些准備工作,繪制各種顏色的紅心:
private Bitmap creatHeart(int color) { int width = bitmap.getWidth(); int height = bitmap.getHeight(); Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(newBitmap); canvas.drawBitmap(bitmap, 0, 0, criPaint); canvas.drawColor(color, PorterDuff.Mode.SRC_ATOP); canvas.setBitmap(null); return newBitmap; }
這里面比較關鍵的代碼只有是 canvas.drawColor(color, PorterDuff.Mode.SRC_ATOP),關於PorterDuff,還是可以去學習了解一下的,很多時候還是很有用的,在這里簡單的介紹一下;
這樣就比較清晰明了了吧,這里使用的就是SRC_ATOP,去心的圖形和顏色重疊部分,就是心了;
這樣只要准備一個心形圖片,就能實現格式各樣的心了;
接下來就是進行根據軌跡進行繪制了,看過第一篇文章的,就應該根據幾個點,就能繪制出來一條軌跡;這里使用屬性動畫,來獲取相對應的軌跡;
首先
/** * 繪制一個增值器 */ class TypeE implements TypeEvaluator<PointF> { private PointF pointFFirst,pointFSecond; public TypeE(PointF start,PointF end){ this.pointFFirst =start; this.pointFSecond = end; } @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { PointF result = new PointF(); float left = 1 - fraction; result.x = (float) (startValue.x*Math.pow(left,3)+3*pointFFirst.x*Math.pow(left,2)*fraction+3*pointFSecond.x*Math.pow(fraction, 2)*left+endValue.x*Math.pow(fraction,3)); result.y= (float) (startValue.y*Math.pow(left,3)+3*pointFFirst.y*Math.pow(left,2)*fraction+3*pointFSecond.y*Math.pow(fraction, 2)*left+endValue.y*Math.pow(fraction,3)); return result; } }
這個很簡單,就是單純的使用公式了,所以說想要繪制復雜的軌跡,我還是要重新拾起來被扔進糞坑的小學數學課本重新看看,當真是熏得淚流滿面啊!!
接下來就很簡單了,只要不停使用屬性動畫,不斷變換位置就好了;
private void moveHeart(final ImageView view){ PointF pointFFirst = this.pointFFirst; PointF pointFSecond = this.pointFSecond; PointF pointFStart = this.pointFStart; PointF pointFEnd = this.pointFEnd; ValueAnimator animator = ValueAnimator.ofObject(new TypeE(pointFFirst, pointFSecond), pointFStart, pointFEnd); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF value = (PointF) animation.getAnimatedValue(); view.setX(value.x); view.setY(value.y); } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); AdvancePathView.this.removeView(view); } }); ObjectAnimator af = ObjectAnimator.ofFloat(view, "alpha", 1f, 0); af.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); AdvancePathView.this.removeView(view); } }); AnimatorSet set = new AnimatorSet(); set.setDuration(3000); set.play(animator).with(af); set.start(); }
就是這么簡單,完全沒有難度啊有木有!!!
總的來說還是三步:
第一
- :繪制各種顏色的心
- 繪制一個增值器,獲取軌跡
- 使用屬性動畫,根據軌跡移動位置
好了,到這里我這一系列的文章就結束了,兩天水時間搞的,感覺稍微有點水,但是就這樣啦,畢竟本身不是很難的東西,有什么問題可以問我,有時間一定會耐心解答的;
最后附上源碼:https://github.com/sangxiaonian/BezierIntroduce.git