用Path来绘制一些图形
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来绘制一些图形的更多相关文章
- 学习笔记:HTML5 Canvas绘制简单图形
HTML5 Canvas绘制简单图形 1.添加Canvas标签,添加id供js操作. <canvas id="mycanvas" height="700" ...
- C# 绘制PDF图形——基本图形、自定义图形、色彩透明度
引言 在PDF中我们可以通过C#程序代码来添加非常丰富的元素来呈现我们想要表达的内容,如绘制表格.文字,添加图形.图像等等.在本篇文章中,我将介绍如何在PDF中绘制图形,并设置图形属性的操作. 文章中 ...
- PyQt5利用QPainter绘制各种图形
这个例子我做了好几天: 1)官网C++的源码,改写成PyQt5版本的代码,好多细节不会转化 2)网上的PyQt的例子根本运行不了 填了无数个坑,结合二者,终于能完成了一个关于绘图的东西.这个过程也掌握 ...
- 利用QPainter绘制各种图形(Shape, Pen 宽带,颜色,风格,Cap,Join,刷子)
利用QPainter绘制各种图形 Qt的二维图形引擎是基于QPainter类的.QPainter既可以绘制几何形状(点.线.矩形.椭圆.弧形.弦形.饼状图.多边形和贝塞尔曲线),也可以绘制像素映射.图 ...
- h5 的canvas绘制基本图形
文章地址:https://www.cnblogs.com/sandraryan/ canvas是一个标签,可用于绘制复杂图形,渲染效果比普通DOM快 某些低版本浏览器不支持 canvas 使用原生几乎 ...
- css绘制特殊图形,meida查询,display inline-box间隙问题以及calc()函数
本文同时发表于本人个人网站 www.yaoxiaowen.com 距离上一篇文章已经一个月了,相比于写代码,发现写文章的确是更需要坚持的事情.言归正传,梳理一下这一个月来,在写ife任务时,有必要记录 ...
- 摘记 史上最强大的40多个纯CSS绘制的图形(一)
今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和网站小图标,真的非常强大,分享给大家. Square(正方 ...
- 40多个纯CSS绘制的图形
本文由码农网 – 陈少华原创,转载请看清文末的转载要求. 今天在国外的网站上看到了很多看似简单却又非常强大的纯CSS绘制的图形,里面有最简单的矩形.圆形和三角形,也有各种常见的多边形,甚至是阴阳太极和 ...
- CSS 魔法系列:纯 CSS 绘制各种图形《系列六》
我们的网页因为 CSS 而呈现千变万化的风格.这一看似简单的样式语言在使用中非常灵活,只要你发挥创意就能实现很多比人想象不到的效果.特别是随着 CSS3 的广泛使用,更多新奇的 CSS 作品涌现出来. ...
随机推荐
- 简单Bat文件编写
@ECHO OFFTITLE 清理Work目录E:cd E:\Android_WorkSpace@ECHO ONecho 开始打包MavenTest......mvn install pause @E ...
- 【Software Clone】2014-IEEE-Towards a Big Data Curated Benchmark of Inter-Project Code Clones
Abstract 大数据的克隆检测和搜索算法已经作为嵌入在应用中的一部分. 本文推出一个代码检测基准.包含一些已知的真假克隆代码.其中包括600万条真克隆(包含type-1,type-2,type-3 ...
- asp.net 客户端上传文件全路径获取方法
asp.net 获取客户端上传文件全路径方法: eg:F:\test\1.doc 基于浏览器安全问题,浏览器将屏蔽获取客户端文件全路径的方法,只能获取到文件的文件名,如果需要获取全路径则需要另想其他 ...
- [IR] Boolean retrieval
How to build Inverted Index? 1. Token sequence. 2. Sort by terms. 3. Dictionary & Postings code ...
- Tips3:通过Layer下拉菜单来锁定游戏物体和控制物体的可视化
通过把不同的游戏物体放在不同的Layer里面能对不同类的游戏物体进行很方便的控制,如果某些游戏物体创建后你不想再改动,如地面 装饰 什么的, 你可以通过点击Layer下拉菜单把它们锁定了 也可以通过控 ...
- 充实你的素材库!10款免费的 PSD 素材下载
由于网页设计师没有时间来自己从零开始设计,所以在设计项目中使用网络上已有的设计素材是常见的方式.这就是为什么我们经常会到网上搜索可以免费下载的素材. 今天,我们这里有几套不同的免费的 PSD 素材分享 ...
- Rainyday.js – 傻眼了!竟然有如此逼真的雨滴效果
Rainyday.js 是一个轻量的 JavaScript 库,利用 HTML5 Canvas 实现雨滴下落在玻璃表面的动画效果.Rainyday.js 尽可能的模拟现实的雨滴效果,几乎可以以假乱真了 ...
- Android 学习笔记之网络通信基础+WebView....
PS:加快学习进度...下周一完成Android网络通信...然后正式进入实战... 学习内容: 1.Android中Http基础... 2.Android中的Socket基础... 3.Androi ...
- QCustomplot使用分享(五) 布局
一.历史对比 关于QCPLayoutElement这个元素的讲解之前,我想先对1.3.2release版本和2.0.0beta版本的该元素做以简单的对比介绍,首先,1.3.2release版本时,鼠标 ...
- JS中 toString() & valueOf()
数据的转换 所有对象继承了两个转换方法: 第一个是toString(),它的作用是返回一个反映这个对象的字符串 第二个是valueOf(),它的作用是返回它相应的原始值 toString() toSt ...