原创

Android 实现赛贝尔曲线介绍及源码分析

什么是贝塞尔曲线?

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。主要结构:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。


贝塞尔曲线的分类 

了解一下贝塞尔曲线,根据影响变量的个数不同,我们可以看到不同类型的曲线。参考资料:http://blog.csdn.net/z82367825/article/details/51599245

 

一阶贝塞尔曲线(线段):

公式: 


意义:由 P0 至 P1 的连续点, 描述的一条线段。


二阶贝塞尔曲线(抛物线)

公式: 



原理: 由 P0 至 P1 的连续点 Q0,描述一条线段。 
           由 P1 至 P2 的连续点 Q1,描述一条线段。 
           由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。

三阶贝塞尔曲线:


 

当然还有四阶曲线、五阶曲线......只不过随着变量的增加,复杂维度会越来越高。

贝塞尔曲线代码实现

我们一般使用的是二阶贝塞尔曲线和三阶贝塞尔曲线,从动态图和公式我们可以看出,贝塞尔曲线主要由于三个部分控制:起点,终点,中间的辅助控制点。如何利用这三个点画出贝塞尔曲线,在android自带的Path类中自带了方法,可以帮助我们实现贝塞尔曲线:

需要的有两个类:

第一个类是实现二阶的:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.view.MotionEvent;
import android.view.View;
/**
 * Created by huqing on 2016/6/27.
 */
public class TwoBezier extends View {
    private Paint mPaint;
    private int centerX, centerY;
    private PointF start, end, fingerPoint;
    /**
     *     使用,例:
     *    TwoBezier mBezier = new TwoBezier(this);
     *    setContentView(mBezier);
     *
     * @param context
     */
    public TwoBezier(Context context) {
super(context);
//画笔
mPaint = new Paint();
mPaint.setStrokeWidth(8);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setTextSize(60);
//三点确定该二阶曲线
start = new PointF(0, 0);
end = new PointF(0, 0);
fingerPoint = new PointF(0, 0);
    }

    /**
     * 手指触碰时获取当前手指坐标
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
// 根据触摸位置更新控制点,并提示重绘
fingerPoint.x = event.getX();
fingerPoint.y = event.getY();
invalidate();//调用onDraw方法
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(fingerPoint.x, fingerPoint.y, mPaint);
// 绘制辅助线
mPaint.setStrokeWidth(4);
canvas.drawLine(start.x, start.y, fingerPoint.x, fingerPoint.y, mPaint);
canvas.drawLine(end.x, end.y, fingerPoint.x, fingerPoint.y, mPaint);
// 绘制贝塞尔曲线
mPaint.setColor(Color.RED);
mPaint.setStrokeWidth(8);
//绘制曲线路径
Path path = new Path();
//起点
path.moveTo(start.x, start.y);
//关键方法:谷歌封装好的贝塞尔曲线绘制方法quadTo,给出控制点和终点
path.quadTo(fingerPoint.x, fingerPoint.y, end.x, end.y);
canvas.drawPath(path, mPaint);
    }

    /**
     * onSizeChanged的启动时间在onDraw之前,初始化该View时获取到长宽
     */
    @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;
//控制点,就是手指移动的那个点
fingerPoint.x = centerX;
fingerPoint.y = centerY - 100;
    }
}

三阶的曲线,具体代码如下:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
 * Created by huqing on 2016/6/27.
 */
public class BezierThree extends View {

    private Paint mPaint;
    private int centerX, centerY;
    private PointF start, end, fingerPointOne, fingerPointTwo;
    private boolean mode = true;
    public BezierThree(Context context) {
this(context, null);
    }
    public BezierThree(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);
fingerPointOne = new PointF(0, 0);
fingerPointTwo = 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 = 10;
start.y = centerY;
end.x = w - 10;
end.y = centerY;
fingerPointOne.x = centerX;
fingerPointOne.y = centerY - 100;
fingerPointTwo.x = centerX;
fingerPointTwo.y = centerY - 100;
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
// 根据触摸位置更新控制点,并提示重绘
if (mode) {
    fingerPointOne.x = event.getX();
    fingerPointOne.y = event.getY();
} else {
    fingerPointTwo.x = event.getX();
    fingerPointTwo.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(fingerPointOne.x, fingerPointOne.y, mPaint);
canvas.drawPoint(fingerPointTwo.x, fingerPointTwo.y, mPaint);
// 绘制辅助线
mPaint.setStrokeWidth(4);
canvas.drawLine(start.x, start.y, fingerPointOne.x, fingerPointOne.y, mPaint);
canvas.drawLine(fingerPointOne.x, fingerPointOne.y, fingerPointTwo.x, fingerPointTwo.y, mPaint);
canvas.drawLine(fingerPointTwo.x, fingerPointTwo.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(fingerPointOne.x, fingerPointOne.y, fingerPointTwo.x, fingerPointTwo.y, end.x, end.y);
canvas.drawPath(path, mPaint);
    }
}
最后调用就好了
setContentView(new BezierThree(this));
~阅读全文-人机检测~

微信公众号“Java精选”(w_z90110),专注Java技术干货分享!让你从此路人变大神!回复关键词领取资料:如Mysql、Hadoop、Dubbo、Spring Boot等,免费领取视频教程、资料文档和项目源码。微信搜索小程序“Java精选面试题”,内涵3000+道Java面试题!

涵盖:互联网那些事、算法与数据结构、SpringMVC、Spring boot、Spring Cloud、ElasticSearch、Linux、Mysql、Oracle等

评论

  1. #1

    (2018/01/16 16:59:35)回复
    一辈子只做好一件事!我是有多么的大方吖!哈哈

  2. #2

    假诗人 (2017/10/23 13:53:44)回复
    哇 博主写的真棒 太厉害了 我都爱死你了

    路人甲 (2017/10/23 14:01:27)回复
    你自己写的自己爱自己,这也有点太自恋了些吧!你这是从别处转载的部分过来的吧,转载尽量留着转载地址或者写上参考地址。

分享:

支付宝

微信