Android 贝赛尔曲线

版权归作者所有,转发请注明出处://www.greatytc.com/p/6f2955dc821d

什么是贝塞尔曲线?

是应用于二维图形应用程序的数学曲线一般在软件开发中我们使用它进行精确的绘制平滑的曲线。

如何绘制一条简单的曲线?

首先我们来看看一些简单的图形

Bizer案例

我们可以看到上面三张图片都是一些比较简单的曲线,那么我们如何使用编程的方式将其是现在界面上了,首先我们对这几张图片进行分析

控制点

我们发现所有曲线都由起始点,控制点(可以有多个),结束点三个部分组成,只要我们能够在显示器上精确的定位这三个部分就能实现曲线的绘制

Android对贝塞尔曲线的支持

在Android中的Path类对贝塞尔曲线进行支持

1 . 对于单个控制点的贝塞尔曲线:
/**
     * Add a quadratic bezier from the last point, approaching control point
     * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
     * this contour, the first point is automatically set to (0,0).
     *
     * @param x1 The x-coordinate of the control point on a quadratic curve
     * @param y1 The y-coordinate of the control point on a quadratic curve
     * @param x2 The x-coordinate of the end point on a quadratic curve
     * @param y2 The y-coordinate of the end point on a quadratic curve
     */
    public void quadTo(float x1, float y1, float x2, float y2) {
        isSimplePath = false;
        native_quadTo(mNativePath, x1, y1, x2, y2);
    }

其中起始点为此Path的上一个连接点,x1,y1为此曲线的控制点,x2,y2为结束点

2 . 对于多个控制点的贝塞尔曲线:
/**
     * Add a cubic bezier from the last point, approaching control points
     * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
     * made for this contour, the first point is automatically set to (0,0).
     *
     * @param x1 The x-coordinate of the 1st control point on a cubic curve
     * @param y1 The y-coordinate of the 1st control point on a cubic curve
     * @param x2 The x-coordinate of the 2nd control point on a cubic curve
     * @param y2 The y-coordinate of the 2nd control point on a cubic curve
     * @param x3 The x-coordinate of the end point on a cubic curve
     * @param y3 The y-coordinate of the end point on a cubic curve
     */
    public void cubicTo(float x1, float y1, float x2, float y2,
                        float x3, float y3) {
        isSimplePath = false;
        native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3);
    }

其中起始点为此Path的上一个连接点,x1,y1为此曲线的第一个控制点,x2,y2为第二个控制点,x3,y3为结束点

3 .实现案例一
Bizer4

案例分析:
1.我们可以将此效果看为是一个波形图
波峰 波长
2.是由多个贝塞尔曲线链接的效果
案例实现:

1.新建一个自定义View,并且重写onDraw方法
public class TestBizerView extends View {

    public TestBizerView(Context context) {
        this(context,null);
    }

    public TestBizerView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public TestBizerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}
2.重写onDraw方法并且初始化画笔设置
     /**
     * 初始化画笔
     */
    Paint mPaint;

    /**
     * 曲线起始点的坐标
     */
    private static int START_X_POINT=0;
    private static int START_Y_POINT=200;

    /**
     * 波长度
     */
    private static int WAVE_LENGTH=200;

    /**
     *波峰高度
     */
    private static int WAVE_HEIGHT=50;

    /**
     * 初始化画笔
     */
    public void init(){
        mPaint=new Paint();
        //1.设置画笔颜色
        mPaint.setColor(Color.RED);
        //2.设置抗锯齿
        mPaint.setAntiAlias(true);
        //3.设置画笔风格
        mPaint.setStyle(Paint.Style.STROKE);
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
    }
3.简单的绘制一个波长(在onDraw中)
    @Override
    protected void onDraw(Canvas canvas) {
         //1.初始化一个Path路径
         Path p=new Path();
         //2.设置路径的起始点(Bizer的起始点)
          p.moveTo(START_X_POINT,START_Y_POINT);
         //3.绘制一个波长的贝塞尔曲线
         //控制点坐标:WAVE_LENGTH/4,START_Y_POINT-WAVE_HEIGHT    
         //结束点坐标:WAVE_LENGTH/2,START_Y_POINT
         p.quadTo(WAVE_LENGTH/4,START_Y_POINT-WAVE_HEIGHT,WAVE_LENGTH/2,START_Y_POINT);
         //以上一次的结束点为起始点
         p.quadTo(WAVE_LENGTH*3/4,START_Y_POINT+WAVE_HEIGHT,WAVE_LENGTH,START_Y_POINT);
         //4.绘制路径
         canvas.drawPath(p,mPaint);
   }
4.在布局中使用此自定义View
    <com.example.hasee.testbizerapp.TestBizerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
一个波长 的Bizer
5.绘制多个波长

需要对OnDraw方法中的代码进行修改

@Override
    protected void onDraw(Canvas canvas) {
        //1.初始化一个Path路径
        Path p=new Path();
        //2.设置路径的起始点(Bizer的起始点)
        p.moveTo(START_X_POINT,START_Y_POINT);
        //3.绘制一个波长的贝塞尔曲线
//        //控制点坐标:WAVE_LENGTH/4,START_Y_POINT-WAVE_HEIGHT
//        //结束点坐标:WAVE_LENGTH/2,START_Y_POINT
//        p.quadTo(WAVE_LENGTH/4,START_Y_POINT-WAVE_HEIGHT,WAVE_LENGTH/2,START_Y_POINT);
//        //以上一次的结束点为起始点
//        p.quadTo(WAVE_LENGTH*3/4,START_Y_POINT+WAVE_HEIGHT,WAVE_LENGTH,START_Y_POINT);
        for (int i = 0; i <20 ; i++) {
                  p.quadTo(WAVE_LENGTH(i*2+1)/4,i%2==0?START_Y_POINTWAVE_HEIGHT:START_Y_POINT+WAVE_HEIGHT,WAVE_LENGTH(i+1)/2,START_Y_POINT);
        }
        //4.绘制路径
        canvas.drawPath(p,mPaint);
    }
Bizer4

代码链接:https://github.com/huangyiCode/TestBizerApp.git

4 .实现案例二

可以增加延时让水波可以动起来

实现案例二

代码链接:https://github.com/huangyiCode/TestBizerTwo

5 .实现案例三

拖拽功能

1.效果演示:
拖拽效果.gif
2.当我们看到有动画效果要实现上述的效果,首先需要把拖拽动画的其中一帧进行拆解,如果明白了一帧的绘制那么其他帧数时候的状态只是大同小异,例如下图:
独立的一帧拆解.png
3.然后去掉填充效果,发现只是由两个圆,以及两条曲线组成,那么构成这张图片只需要下列元素
独立的一帧拆解(无填充).png
4.主要的定位元素:

1.两个圆的圆心以及半径用来绘制圆形
2.两条曲线的起始点以及控制点

如图所示我们可以发,圆形的位置会跟随手指的位置移动 只是起始位置的圆大小会发生变化,以及拖拽部位圆的圆心会发生变化,这些用来定位绘制圆形的元素都比较容易获取,控制点如图我们可以分析出其实就是两条圆心的终点,那么难点就在如我们如何计算获取曲线起始点位置的坐标,如果我们可以根据圆的位置计算出动态起始点的坐标,那么久很容易实现上述演示的效果

主要端点.png

5.如何计算曲线起始点位置的坐标,我们来看下分析图,添加了一些辅助线,就像我们做几何题一样
偏移角度.png

如图所示,根据绿色部位,我们可以根据三角函数计算出拖拽圆相对于起始圆所偏移的角度,并且根据此角度我们可以计算出对应曲线起始点的坐标,我们可以看出下图三个位置的角度是相同的,如果我们计算出了绿色部位的角度那么就可以使用半径根据三角函数计算出曲线的对应端点位置的偏移量坐标,从而将其进行绘制,当我们掌握如何绘制一帧的数据之后,我们就很容易绘制动态的变化效果,只需要在监听View的触摸事件,当拖拽位置坐标发生变化之后重新绘制当前UI,从而达到动画效果


曲线端点计算.jpg

代码链接:
https://github.com/huangyiCode/TestBizerTwo/blob/master/app/src/main/java/com/example/hasee/testbizertwo/DragView.kt

6 .实现案例四

曲线.PNG

代码链接:
https://github.com/huangyiCode/TestBizerTwo/blob/master/app/src/main/java/com/example/hasee/testbizertwo/CircleView.kt

欢迎关注Mike的简书

Android 知识整理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 198,082评论 5 464
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,231评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 145,047评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,977评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,893评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,014评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,976评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,605评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,888评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,906评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,732评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,513评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,980评论 3 301
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,132评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,447评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,027评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,232评论 2 339