Path是android中用来封装几何学路径的一个类,因为Path在图形绘制上占的比重还是相当大的。你可以用它来绘制各种样式的几何图形,做图表什么的都可以。

一、画线段

1.1 lineT(float x, float y)

先来看一段代码:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(); // 实例化路径
mPath = new Path();
// 连接路径到点[100,100]
mPath.lineTo(, );
// 绘制路径
canvas.drawPath(mPath, mPaint);
}

效果就是将起始点和(100,100)进行连接。这里因为没有设置起始点,所以默认是canvas的左上角,而这里默认的canvas和屏幕重合,所以就成了这个样子。

当然我们可以考虑多次调用lineTo方法来绘制更复杂的图形:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
mPath.moveTo(100, 100);
// 连接路径到点
mPath.lineTo(300, 100);
mPath.lineTo(400, 200);
mPath.lineTo(200, 200);
// 绘制路径
canvas.drawPath(mPath, mPaint);
}

1.2 moveTo(float x, float y)  

我们可以通过moveTo(float x, float y) 来移动起始的坐标点,比如:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
//移动点至[300,300]
mPath.moveTo(300, 300);
// 连接路径到点[100,100]
mPath.lineTo(100, 100);
// 绘制路径
canvas.drawPath(mPath, mPaint);
}

1.3 close()

上面的例子我们构建了一个类似平行四边形的图像,如果此时我们想闭合该曲线让它变成一个形状该怎么做呢?聪明的你一定想到:

mPath.lineTo(100, 100)  

然而Path给我提供了更便捷的方法:

close()

在上面的例子添加close()后就会自动构建一条末点和起始点的线段:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
mPath.moveTo(100, 100);
// 连接路径到点
mPath.lineTo(300, 100);
mPath.lineTo(400, 200);
mPath.lineTo(200, 200);
// 闭合曲线
mPath.close();
// 绘制路径
canvas.drawPath(mPath, mPaint);
}

二、画贝赛尔曲线

2.1 贝赛尔曲线

什么叫贝赛尔曲线?其实很简单,使用三个或多个点来确定的一条曲线,贝塞尔曲线在图形图像学中有相当重要的地位,Path中也提供了一些方法来给我们模拟低阶贝赛尔曲线。

贝塞尔曲线的定义也比较简单,你只需要一个起点、一个终点和至少零个控制点则可定义一个贝赛尔曲线,当控制点为零时,只有起点和终点,此时的曲线说白了就是一条线段,我们称之为一阶贝赛尔曲线。

PS:以下图片和公式均来自维基百科和互联网

一阶贝赛尔曲线:

其公式可概括为:

其中B(t)为时间为t时点的坐标,P0为起点、Pn为终点

贝塞尔曲线于1962年由法国数学家Pierre Bézier第一次研究使用并给出了详细的计算公式,So该曲线也是由其名字命名。Path中给出的quadTo方法属于

二阶贝赛尔曲线:

二阶贝赛尔曲线的一个明显特征是其拥有一个控制点,大家可以这样想想贝赛尔曲线,在一根两端固定橡皮筋上有一块磁铁,现在我们拿另一块磁铁去吸引橡皮筋上的磁铁,因为引力,橡皮筋会随着我们手上磁铁的移动而改变形状,又因为橡皮筋的张力让束缚在橡皮筋上的磁铁不会轻易吸附到我们手上的磁铁,这时橡皮筋的状态就可以看成是一条贝塞尔曲线,而我们手中的磁铁就是一个控制点,通过这个控制点我们“拉扯”橡皮筋的曲度。

二阶贝赛尔曲线的公式为:

同样的,Path中也提供了三阶贝塞尔曲线的方法cubicTo,按照上面我们的推论,三阶应该是有两个控制点才对对吧

三阶贝赛尔曲线:

公式:

高阶贝赛尔曲线在Path中没有对应的方法,对我们来说三阶也足够了,不过大家可以了解下,难得我在墙外找到如此动感的贝赛尔曲线高清无码动图

高阶贝塞尔曲线:

四阶:

五阶:

贝塞尔曲线通用公式:

2.2 quadTo(float x1, float y1, float x2, float y2)

上面说了一阶的就是一条线段,所以直接来看二阶。下面的方法可以让我们绘制“二阶”贝赛尔曲线。

quadTo(float x1, float y1, float x2, float y2)

解释:其中quadTo的前两个参数为控制点的坐标,后两个参数为终点坐标,至于起点默认是画布的左上角。这里的p0就是起点,(x1,y1)就是中点P1,(x2,y2)就是末端点P2。

现在,我们使用它来绘制一条曲线:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动起点至[100,100]
mPath.moveTo(100, 100); // 连接路径到点
mPath.quadTo(200, 200, 300, 100);
canvas.drawPath(mPath, mPaint);
}

效果:

 示意图: 

2.3 cubicTo(float x1, float y1, float x2, float y2, float x3, float y3)  

它可以绘制三阶贝赛尔曲线。

与quadTo类似,前四个参数表示两个控制点,最后两个参数表示终点。其实,(x1,y1)就是P1,(x2,y2)是P2,(x3,y3)是P3。

下面用代码来绘制一下:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动起点至[100,100]
mPath.moveTo(100, 100); // 连接路径到点
mPath.cubicTo(200, 200, 300, 0, 400, 100);
canvas.drawPath(mPath, mPaint);
}

  示意图: 

三、画弧线

arcTo (RectF oval, float startAngle, float sweepAngle)

是一个画弧线的方法,其实说白了就是从圆或椭圆上截取一部分而已。

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动起点至[100,100]
mPath.moveTo(100, 100);
// 连接路径到点
RectF oval = new RectF(100, 100, 200, 200);
mPath.arcTo(oval, 0, 90);
canvas.drawPath(mPath, mPaint);
}

上面的代码首先构建出一个矩形区域,这个区域内就是椭圆和园的区域,椭圆或园会内切于这个矩形区域。然后我们设置圆弧的其实角度和最终角度来截取圆弧。

注意:使用Path生成的路径必定都是连贯的,虽然我们使用arcTo绘制的是一段弧但其最终都会与我们的起始点[100,100]连接。

如果你不想连怎么办?Path也提供了另一个重载方法:

arcTo (RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo)

它会强制起点为绘制的起始点,而不是画布的左上角。我们来看看效果:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动起点至[100,100]
mPath.moveTo(100, 100);
// 连接路径到点
RectF oval = new RectF(100, 100, 200, 200);
mPath.arcTo(oval, 0, 90,true);
canvas.drawPath(mPath, mPaint);
}

四、rXXXTo方法

Path中除了上面介绍的几个XXXTo方法外还有一套rXXXTo方法:

rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3)
rLineTo(float dx, float dy)
rMoveTo(float dx, float dy)
rQuadTo(float dx1, float dy1, float dx2, float dy2)

这一系列rXXXTo方法其实跟上面的那些XXXTo差不多的,唯一的不同是rXXXTo方法的参考坐标是相对的而XXXTo方法的参考坐标始终是参照画布原点坐标,什么意思呢?举个简单的例子:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动点至[100,100]
mPath.moveTo(100, 100); // 连接路径到点
mPath.lineTo(200, 200);
canvas.drawPath(mPath, mPaint);
}

这里的move和lineTo的坐标都是对于画布左上角(0,0)来说的,是一个绝对坐标。而我们换为mPath.rLineTo(200, 200); 后呢?

是不是感觉线段长了很多,因为这里的(200,200)是相对于开始点(100,100)来说的,是相对坐标。如果换算成绝对坐标就是绘制一条(100,100)到(300,300)之间的线段。其实,这个前缀“r”也就是relative(相对)的简写!

五、addXXX方法

XXXTo方法可以连接Path中的曲线而Path提供的另一系列addXXX方法则可以让我们直接往Path中添加一些曲线,比如

addArc(RectF oval, float startAngle, float sweepAngle)

它允许我们将一段弧形添加至Path,注意这里我用到了“添加”这个词汇,也就是说,通过addXXX方法添加到Path中的曲线是不会和上一次的曲线进行连接的:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5); // 实例化路径
mPath = new Path();
// 移动点至[100,100]
mPath.moveTo(100, 100); // 连接路径到点
mPath.lineTo(200, 200);
// 添加一条弧线到Path中
RectF oval = new RectF(100, 100, 300, 400);
mPath.addArc(oval, 0, 90); canvas.drawPath(mPath, mPaint);
}

如图和代码所示,虽然我们先绘制了由[100,100]到[200,200]的线段,但是在我们往Path中添加了一条弧线后该弧线并没与线段连接。

除了addArc,Path还提供了一系列的add方法:

addCircle(float x, float y, float radius, Path.Direction dir)
addOval(float left, float top, float right, float bottom, Path.Direction dir)
addRect(float left, float top, float right, float bottom, Path.Direction dir)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry, Path.Direction dir)

这些方法和addArc有很明显的区别,就是多了一个Path.Direction参数,其他呢都大同小异,除此之外不知道大家还发现没有,addArc是往Path中添加一段弧,说白了就是一条开放的曲线,而上述几种方法都是一个具体的图形,或者说是一条闭合的曲线,Path.Direction的意思就是标识这些闭合曲线的闭合方向。Path.Direction只有两个常量值CCW和CW分别表示逆时针方向闭合和顺时针方向闭合。

那什么叫闭合方向呢?光说大家一定会蒙,有学习激情的童鞋看到后肯定会马上敲代码试验一下两者的区别,可是不管你如何改,单独地在一条闭合曲线上你是看不出所谓闭合方向的区别的。为了弄懂它,我们在path上绘制一些文字来说明最后参数的意义:

    @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE); // 实例化路径
mPath = new Path();
// 移动起点至[100,100]
mPath.moveTo(100, 100); // 添加一条弧线到Path中
RectF oval = new RectF(100, 100, 300, 400);
mPath.addOval(oval, Path.Direction.CW); canvas.drawPath(mPath, mPaint); mPaint.setTextSize(50);
// 绘制路径上的文字
canvas.drawTextOnPath("123456789", mPath, 0, 0, mPaint);
}

如果我们换作:

mPath.addOval(oval, Path.Direction.CCW); 

绘制的文字全都沿着Path跑到闭合曲线的“内部”了。

文章中大部分内容参考自:http://blog.csdn.net/aigestudio/article/details/41960507,本人对原文有少量的删减。本文记录在此,仅供学习之用,感谢原作者分享。

From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige ,感谢原作者。

用Path来绘制一些图形的更多相关文章

  1. 学习笔记:HTML5 Canvas绘制简单图形

    HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...

  2. C# 绘制PDF图形——基本图形、自定义图形、色彩透明度

    引言 在PDF中我们可以通过C#程序代码来添加非常丰富的元素来呈现我们想要表达的内容,如绘制表格.文字,添加图形.图像等等.在本篇文章中,我将介绍如何在PDF中绘制图形,并设置图形属性的操作. 文章中 ...

  3. PyQt5利用QPainter绘制各种图形

    这个例子我做了好几天: 1)官网C++的源码,改写成PyQt5版本的代码,好多细节不会转化 2)网上的PyQt的例子根本运行不了 填了无数个坑,结合二者,终于能完成了一个关于绘图的东西.这个过程也掌握 ...

  4. 利用QPainter绘制各种图形(Shape, Pen 宽带,颜色,风格,Cap,Join,刷子)

    利用QPainter绘制各种图形 Qt的二维图形引擎是基于QPainter类的.QPainter既可以绘制几何形状(点.线.矩形.椭圆.弧形.弦形.饼状图.多边形和贝塞尔曲线),也可以绘制像素映射.图 ...

  5. h5 的canvas绘制基本图形

    文章地址:https://www.cnblogs.com/sandraryan/ canvas是一个标签,可用于绘制复杂图形,渲染效果比普通DOM快 某些低版本浏览器不支持 canvas 使用原生几乎 ...

  6. css绘制特殊图形,meida查询,display inline-box间隙问题以及calc()函数

    本文同时发表于本人个人网站 www.yaoxiaowen.com 距离上一篇文章已经一个月了,相比于写代码,发现写文章的确是更需要坚持的事情.言归正传,梳理一下这一个月来,在写ife任务时,有必要记录 ...

  7. 摘记 史上最强大的40多个纯CSS绘制的图形(一)

    今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和网站小图标,真的非常强大,分享给大家. Square(正方 ...

  8. 40多个纯CSS绘制的图形

    本文由码农网 – 陈少华原创,转载请看清文末的转载要求. 今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和 ...

  9. CSS 魔法系列:纯 CSS 绘制各种图形《系列六》

    我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...

随机推荐

  1. C#简易播放器(基于开源VLC)

    可见光通信技术(Visible Light Communication,VLC)是指利用可见光波段的光作为信息载体,不使用光纤等有线信道的传输介质,而在空气中直接传输光信号的通信方式.LED可见光通信 ...

  2. 解决Eclipse报errors running builder ‘javascript validator’ on project

    导入jquery的js到项目中,Eclipse每次检测到功能代码变化(保存动作触发)就报错: errors running builder ‘javascript validator’ on proj ...

  3. HTML5[3]:中文换行

    保证中文每行第一个字,不会出现标点符号 p { white-space: pre-wrap; }

  4. `cocos2dx非完整` 日志模块 增量更新

    在上一篇文章中,说到了"流程"的由来,以及我对流程的使用. 这一片就是对流程的应用.前一篇文章中说到了三条流程 check_log_measure, check_env_measu ...

  5. libtool: link: `dftables.lo' is not a valid libtool object

    手误造成的错误: make & make install.&位操作符导致的错误!应该是make && make install.

  6. 【转载】如何使用 gnome-screenshot 截图命令

    转载自:http://www.linuxeden.com/html/softuse/20130726/141753.html 日常工作中,我们经常需要截取屏幕状态来给其他人看.一般情况下,我们能最直接 ...

  7. iOS-UIButton-设置button标题和图片位置

    一.效果图 1.Button被点击之前 2.Button被点击之后 二.代码 - (void)createBtn3 { UIImage * buttonImage = [UIImage imageNa ...

  8. Javascript起源...

    Javascript的设计思路是这样的: (1)借鉴C语言的基本语法: (2)借鉴Java语言的数据类型和内存管理: (3)借鉴Scheme语言,将函数提升到"第一等公民"(fir ...

  9. 用Javascript实现回到顶部效果

    用Javascript实现回到顶部效果 经常看到网页中有回到顶部的效果,今天也研究一下回到顶部有哪些方法.众所周知,用锚链接是实现回到最简单的方法,但是从用户体验效果来说,并不是最好的.(锚链接回到顶 ...

  10. sprint5.0

    团队成员完成自己认领的任务. 燃尽图:理解.设计并画出本次Sprint的燃尽图的理想线.参考图6. 每日立会更新任务板上任务完成情况.燃尽图的实际线,分析项目进度是否在正轨.每天的例会结束后的都为任务 ...