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. 2^x mod n = 1(欧拉定理,欧拉函数,快速幂乘)

    2^x mod n = 1 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  2. 为android项目集成maven

    为什么要为android项目增加maven集成功能呢?这里我想到几个主要理由: 部署测试人员和开发人员的角色分离,让他们摆脱eclipse开发环境设置android sdk环境,直接在服务器上运行一个 ...

  3. SNF开发平台WinForm之十三-单独从服务器上获取PDF文件进行显示-SNF快速开发平台3.3-Spring.Net.Framework

    1运行效果: 2开发实现: 如果需要单独显示PDF文件时用下面代码去实现,指定url地址. 地址: . 获取附件管理的实体对象: List<KeyValuePair<string, obj ...

  4. Struts2知多少(1) Struts2 MVC架构

    模型视图控制器(Model View Controller)或MVC,MVC是俗称,是一种软件设计模式,用于开发Web应用程序.模型 - 视图 - 控制器模式是由以下三个部分组成: Model - 模 ...

  5. [转]relative、absolute和float

    position:relative和position:absolute都可以改变元素在文档中的位置,都能激活元素的left.top.right.bottom和z-index属性.(默认这些属性未激活, ...

  6. Rainyday.js – 傻眼了!竟然有如此逼真的雨滴效果

    Rainyday.js 是一个轻量的 JavaScript 库,利用 HTML5 Canvas 实现雨滴下落在玻璃表面的动画效果.Rainyday.js 尽可能的模拟现实的雨滴效果,几乎可以以假乱真了 ...

  7. SQL SERVER 分布式事务(DTC)

    BEGIN DISTRIBUTED TRANSACTION指定一个由 Microsoft 分布式事务处理协调器 (MS DTC) 管理的 Transact-SQL 分布式事务的起始. 语法BEGIN ...

  8. Scrum 1.0

    1.确定选题. 应用NABCD模型,分析你们初步选定的项目,充分说明你们选题的理由. 录制为演说视频,上传到视频网站,并把链接发到团队博客上. 项目:一个售书网站(O2O) 下面是NABCD模型: 1 ...

  9. Sql订阅发布注意事项

    1.做订阅发布的2台Sql服务器最好要版本一致,不能出现类似如下情况: Sql2008 R2[发布] - Sql2008[订阅]: Sql2008 R2[发布] - Sql2012[订阅] 2.订阅发 ...

  10. SignalR简单示例教程入门版

    上周五最后一天在公司上班,无聊之余就想做点什么.介于之前有人让我做个简易版的在线聊天的,于是乎就打算花一天时间来弄下关于SignalR的简单教程制作一个在线的聊天的. 1:前端用了国产的一个MVVM框 ...