1. 程式人生 > >Android開發——貝塞爾曲線解析

Android開發——貝塞爾曲線解析

相信很多同學都知道“貝塞爾曲線”這個詞,我們在很多地方都能經常看到。利用“貝塞爾曲線”可以做出很多好看的UI效果,本篇部落格就讓我們一起學習“貝塞爾曲線”。

貝塞爾曲線的原理

貝塞爾曲線是用一系列點來控制曲線狀態的,這些點簡單分為兩類:

型別作用
資料點確定曲線的起始和結束位置
控制點確定曲線的彎曲程度

一階貝塞爾曲線 
一階曲線是沒有控制點的,僅有兩個資料點(A 和 B),最終效果一個線段。 一階曲線其實就是lineTo方法

這裡寫圖片描述

二階貝塞爾曲線 
在平面內任選 3 個不共線的點,依次用線段連線。 
這裡寫圖片描述

在第一條線段上任選一個點 D。計算該點到線段起點的距離 AD,與該線段總長 AB 的比例。 
這裡寫圖片描述

連線這兩點DE。 E點滿足AD:AB = BE:BC。
這裡寫圖片描述

從新的線段 DE 上再次找出相同比例的點 F,使得 DF:DE = AD:AB = BE:BC。

這裡寫圖片描述

到這裡,我們就確定了貝塞爾曲線上的一個點 F。接下來,讓選取的點D從起點 A 移動到終點 B,F的軌跡就是二階貝塞爾曲線。

這裡寫圖片描述

動態過程如下,二階曲線其實就是quadTo方法
這裡寫圖片描述

三階貝塞爾曲線 
控制點個數為4 時,就是三階的曲線。
這裡寫圖片描述

同理滿足AE:AB = BF:BC = CG:CD = EH:EF = FI:FG = HJ:HI,其中點J軌跡即為三階貝塞爾曲線。 
這裡寫圖片描述

這樣我們得到的是一條三次貝塞爾曲線。 
這裡寫圖片描述

動態圖如下,三階曲線對應的方法是cubicTo
這裡寫圖片描述 

學習貝塞爾曲線函式

一階曲線是一條線段,非常簡單,不再進行介紹,都是path的基本用法。

二階曲線: 
首先,兩個資料點是控制貝塞爾曲線開始和結束的位置,而控制點則是控制貝塞爾的彎曲狀態。
這裡寫圖片描述

從上面的動態圖可以看出,貝塞爾曲線在動態變化過程中有類似於橡皮筋一樣的彈性效果,因此在製作一些彈性效果的時候很常用。

程式碼如下:

public class Bezier extends View {

    private Paint mPaint;
    private int centerX, centerY;

    private PointF start, end, control;

    public Bessel1(Context context) {
        super
(context); mPaint = new Paint(); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(8); mPaint.setStyle(Paint.Style.STROKE); mPaint.setTextSize(60); start = new PointF(0,0); end = new PointF(0,0); control = new PointF(0,0); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); centerX = w/2; centerY = h/2; // 初始化資料點和控制點的位置 start.x = centerX-200; start.y = centerY; end.x = centerX+200; end.y = centerY; control.x = centerX; control.y = centerY-100; } @Override public boolean onTouchEvent(MotionEvent event) { // 根據觸控位置更新控制點,並提示重繪 control.x = event.getX(); control.y = event.getY(); invalidate(); return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 繪製資料點和控制點 mPaint.setColor(Color.GRAY); mPaint.setStrokeWidth(20); canvas.drawPoint(start.x,start.y,mPaint); canvas.drawPoint(end.x,end.y,mPaint); canvas.drawPoint(control.x,control.y,mPaint); // 繪製輔助線 mPaint.setStrokeWidth(4); canvas.drawLine(start.x,start.y,control.x,control.y,mPaint); canvas.drawLine(end.x,end.y,control.x,control.y,mPaint); // 繪製貝塞爾曲線 mPaint.setColor(Color.RED); mPaint.setStrokeWidth(8); Path path = new Path(); path.moveTo(start.x,start.y); path.quadTo(control.x,control.y,end.x,end.y); canvas.drawPath(path, mPaint); } }
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

三階曲線: 
三階曲線由兩個資料點和兩個控制點來控制曲線狀態。 
這裡寫圖片描述

public class Bezier2 extends View {

    private Paint mPaint;
    private int centerX, centerY;

    private PointF start, end, control1, control2;
    private boolean mode = true;

    public Bezier2(Context context) {
        this(context, null);

    }

    public Bezier2(Context context, AttributeSet attrs) {
        super(context, attrs);

        mPaint = new Paint();
        mPaint.setColor(Color.BLACK);
        mPaint.setStrokeWidth(8);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setTextSize(60);

        start = new PointF(0, 0);
        end = new PointF(0, 0);
        control1 = new PointF(0, 0);
        control2 = new PointF(0, 0);
    }

    public void setMode(boolean mode) {
        this.mode = mode;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        centerX = w / 2;
        centerY = h / 2;

        // 初始化資料點和控制點的位置
        start.x = centerX - 200;
        start.y = centerY;
        end.x = centerX + 200;
        end.y = centerY;
        control1.x = centerX;
        control1.y = centerY - 100;
        control2.x = centerX;
        control2.y = centerY - 100;

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 根據觸控位置更新控制點,並提示重繪
        if (mode) {
            control1.x = event.getX();
            control1.y = event.getY();
        } else {
            control2.x = event.getX();
            control2.y = event.getY();
        }
        invalidate();
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //drawCoordinateSystem(canvas);

        // 繪製資料點和控制點
        mPaint.setColor(Color.GRAY);
        mPaint.setStrokeWidth(20);
        canvas.drawPoint(start.x, start.y, mPaint);
        canvas.drawPoint(end.x, end.y, mPaint);
        canvas.drawPoint(control1.x, control1.y, mPaint);
        canvas.drawPoint(control2.x, control2.y, mPaint);

        // 繪製輔助線
        mPaint.setStrokeWidth(4);
        canvas.drawLine(start.x, start.y, control1.x, control1.y, mPaint);
        canvas.drawLine(control1.x, control1.y,control2.x, control2.y, mPaint);
        canvas.drawLine(control2.x, control2.y,end.x, end.y, mPaint);

        // 繪製貝塞爾曲線
        mPaint.setColor(Color.RED);
        mPaint.setStrokeWidth(8);

        Path path = new Path();

        path.moveTo(start.x, start.y);
        path.cubicTo(control1.x, control1.y, control2.x,control2.y, end.x, end.y);

        canvas.drawPath(path, mPaint);
    }
}
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 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
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95

三階曲線相比於二階曲線可以製作更加複雜的形狀,但是對於高階的曲線,用低階的曲線組合也可達到相同的效果,就是傳說中的降階。因此我們對貝塞爾曲線的封裝方法一般最高只到三階曲線。

降階與升階

型別釋義變化
降階在保持曲線形狀與方向不變的情況下,減少控制點數量,即降低曲線階數方法變得簡單,資料點變多,控制點可能減少,靈活性變弱
升階在保持曲線形狀與方向不變的情況下,增加控制點數量,即升高曲線階數方法更加複雜,資料點不變,控制點增加,靈活性變強

貝塞爾曲線例項

一般使用貝塞爾曲線的情況如下:

序號內容用例
1事先不知道曲線狀態,需要實時計算時方天氣預報氣溫變化的平滑折線圖
2顯示狀態會根據使用者操作改變時QQ小紅點,模擬翻書效果
3一些比較複雜的運動狀態(配合PathMeasure使用)複雜運動狀態的動畫效果

至於只需要一個靜態的曲線圖形的情況,用圖片豈不是更好,大量的計算會很不划算。

如果是顯示SVG向量圖的話,已經有相關的解析工具了(內部依舊運用的有貝塞爾曲線),不需要手動計算。

貝塞爾曲線的主要優點是可以實時控制曲線狀態,並可以通過改變控制點的狀態實時讓曲線進行平滑的狀態變化。

QQ紅點的實現效果

qq的紅點去除效果,其實就是用了兩條貝塞爾曲線。 
這裡寫圖片描述

基本理論:只要在拖動的時候 去改變輔助點的Y,和固定圓的半徑, 就可以出來效果。

建立畫筆


        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);


        mPaint.setColor(Color.RED);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

繪製動圓和固定圓

 /**
     * 固定圓  並且初始化
     */
    private PointF mFixedCircle = new PointF(150f, 150f);

    /**
     * 固定圓的半徑
     */
    float mFixedRadius = 14f;

    /**
     * 動圓  並且初始化
     */
    private PointF mDragCircle = new PointF(80f, 80f);

    /**
     * 動圓半徑
     */
    float mDragRadius = 20f;

    /**
     * 動圓兩個焦點的座標
     */
    private PointF[] mDragPoints;

    /**
     * 固定圓的兩個焦點座標
     */
    private PointF[] mFixedPoints;

    /**
     * 控制焦點
     */
    private PointF mControlPoint;
  • 1
  • 相關推薦

    Android開發——曲線解析

    相信很多同學都知道“貝塞爾曲線”這個詞,我們在很多地方都能經常看到。利用“貝塞爾曲線”可以做出很多好看的UI效果,本篇部落格就讓我們一起學習“貝塞爾曲線”。貝塞爾曲線的原理貝塞爾曲線是用一系列點來控制曲線狀態的,這些點簡單分為兩類:型別作用資料點確定曲線的起始和結束位置控制點確定曲線的彎曲程度一階貝塞爾曲線 

    iOS開發-曲線UIBezierPath+進度環

    使用CAShapeLayer與UIBezierPath可以實現不在view的drawRect方法中就畫出一些想要的圖形 。 貝塞爾曲線只是規劃了一個Layer的路徑,而不能真正的展示出來,所以要和CAShapeLayer搭配使用。 //讓貝塞爾曲線與CAShapeLayer

    Android開源專案解析】QQ“一鍵下班”功能實現解析——學習Path及曲線的基本使用

    早在很久很久以前,QQ就實現了“一鍵下班”功能。何為“一鍵下班”?當你QQ有資訊時,下部會有資訊數量提示紅點,點選拖動之後,就會出現“一鍵下班”效果。本文將結合github上關於此功能的一個簡單實現,介紹這個功能的基本實現思路。 專案地址

    Android開發之Path的高階用法用曲線繪製波浪線

    前言:貝塞爾曲線分為一級曲線,二級曲線,三級曲線和多級曲線,利用貝塞爾曲線可以做出很多有意思的動畫和圖形,今天我們就來實現一個比較簡單的波浪線。 -----------------分割線--------------- 初步認識貝塞爾曲線: mPath.moveTo:設定起點

    Android仿蘋果版QQ下拉重新整理實現(二) ——曲線開發"鼻涕"下拉粘連效果

    前言 下面上一下本章需要實現的效果圖: 大家看到這個效果肯定不會覺得陌生,QQ已經把粘滯效果做的滿大街都是,相信不少讀者或多或少對於貝塞爾曲線有所瞭解,不瞭解的朋友們也沒有關係,在這裡我會帶領讀者領略一下貝塞爾的魅力! 一、關於貝塞爾曲線 我們知道

    Android開發曲線進階篇(仿直播送禮物,餓了麼購物車動畫)

    又是一年畢業季,今年終於輪到我了,最近一邊忙著公司的專案,一邊趕著畢設和論文,還私下和朋友搞了些小外包,然後還要還抽出時間寫部落格,真是忙的不要不要的。 好了,言歸正傳,前幾天寫了一篇關於貝塞爾曲線的基礎篇,如果你對貝塞爾曲線還不是很瞭解,建議你先去閱讀下:Android開發之貝塞爾曲線初體驗 ,今天這篇文

    Android曲線應用-跳動的水滴

    dir 貝塞爾曲線 href 完成 通過 android load 繪制 canvas 主要通過6個控制點實現。 val startPoint = PointF() val endPoint = PointF() val control1 = PointF() val c

    【Unity3d遊戲開發】遊戲中的曲線以及其在Unity中的實現

    轉載收藏:原文連結https://www.cnblogs.com/msxh/p/6270468.html 閱讀目錄 一、簡介 二、公式 三、實現與應用   RT,馬三最近在參與一款足球遊戲的開發,其中涉及到足球的各種運動軌跡和路徑,比如射門的軌跡,高吊球

    曲線開發的藝術

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    專案開發中的曲線

    本文由鄒啟文授權網易雲社群釋出。 郵箱大師PC版中,設計師提出了一個很妙的想法: 發信時,出現一個飛機,從寫信中央飛往進度目的地。  附加要求: 1,飛行曲線,飛機先加速,然後減速抵達終點 2,飛行途中,需要轉換飛機朝向 3,飛行途中,飛機漸漸變小 

    android流式佈局、待辦事項應用、曲線、MVP+Rxjava+Retrofit、藝術圖片應用等原始碼

    Android精選原始碼 android模仿淘寶首頁效果原始碼 一款藝術圖片應用,採用T-MVVM打造 Android MVP + RxJava + Retrofit專案 android流式佈局實現熱門標籤效果 android仿淘寶客戶端商品詳

    Android曲線實現水波紋的效果

    前兩天朋友找我實現一個水波紋的效果,因為這塊一直沒做過,所以花了一上午時間研究一下,參考了網上的一些方法,得知Android還有Path.quadTo()這麼一個方法。 話不多說,程式碼如下: public class MyView extends View implem

    2014-11-6Android學習------Android 模擬翻頁效果實現--------曲線(二)

    寫一篇文章很辛苦啊!!! 轉載請註明,聯絡請郵件[email protected] 我學習Android都是結合原始碼去學習,這樣比較直觀,非常清楚的看清效果,覺得很好,今天的學習原始碼是網上找的原始碼 百度搜就知道很多下載的地方  網上原始碼的名字叫:A

    Android自定義View——曲線實現水波紋進度球

    效果圖 原理分析 首先需要了解的水波紋實現效果,可以在部落格的自定義View專題找到,其實現原理如下 利用貝塞爾曲線繪製螢幕外和螢幕內的sin曲線 利用path將sin曲線的左下角和右下角連線起來成為一塊區域 通過不斷的平移sin曲線,然後平移完

    Android 控制元件沿曲線運動(中)

    看了Android貝塞爾曲線屬性動畫(上)是不是在罵我SB,換個貝塞爾曲線的起始點,控制點,終點,控制元件還是按原來路徑運動,So.... 下面我實現了控制元件在隨機的一個貝塞爾曲線上的運動 package com.example.propertyanimsecdemo;

    Android自定義View進階 - 曲線

                    Path之貝塞爾曲線 作者微博: @GcsSloop 【本系列相關文章】 在

    Android自定義View阻尼動畫&曲線的實現

    效果圖:直接上程式碼啦:package com.example.administrator.myapplication.customview; import android.animation.Animator; import android.animation.Anim

    Android-曲線

    從去年開始瞭解貝塞爾曲線之後,發現開發中,不管是Android/Ios平臺,還是web前端等,都有貝塞爾曲線的應用,通過繪製貝塞爾曲線,可以幫助開發者實現很多效果,例如一段時間內很流行的粘合型的下拉重新整理、又如天氣曲線圖,同時,以貝塞爾曲線為基礎的貝塞爾工具是所有繪圖軟

    Android 繪圖基礎:Path(繪製三角形、曲線、正餘弦)

    學習重點: 理解path的使用 理解貝塞爾曲線的繪製原理 可動正餘弦的繪製 Path的簡單介紹   在 Android 繪圖基礎:Canvas畫布——自定義View(繪製錶盤、矩形、圓形、弧、漸變) 中我們可以看到Canvas的強大功能,其實Canva

    Android曲線 二階的簡單處理

    二階效果圖 控制點只有一個 private float mStartPointX; private float mStartPointY; private float mEndPointX; private fl