上一篇Canvas的绘制图形只能绘制一些常规的,比如点、线、圆、椭圆、矩形等的。如果想要绘制更复杂的图形,那么就得靠Path了。

Path的定义:
Path类将多种符合路径(多个轮廓,如直线段、二次曲线、立方曲线等)封装在其内部的几何路径。

Path的绘制:
通过设置Paint.Style的FILL(只描内容)、STROKE(只描边)、FILL_AND_STROKE(描边和内容),然后调用canvas.drawPath(path, paint);Path还可以用于剪切或者在路径上绘制文本canvas.drawTextOnPath()。

Path有两个构造函数

Path() // 空的构造函数
Path(Path src) //创建一个新的路径,并且从src路径里赋值内容

Path一些常用的API:

功能分类 Path的常用API 备注
线操作 lineTo、rLineTo 绘制线

点操作 moveTo、rMoveTo 改变后面操作的起始点位置 setLastPoint 改变前面操作中最后点的位置 常规图形操作 addRect 绘制矩形 addRoundRect 绘制圆角矩形 addCircle 绘制圆 addOval 绘制椭圆 addArc、arcTo 绘制圆弧 闭合path操作 close 如果连接Path起点和终点能形成一个闭合图形,则会将起点和终点连接起来形成一个闭合图形 贝塞尔曲线 quadTo、rQuadTo、cubicTo、rCubicTo 贝塞尔曲线

###线操作

lineTo(float x, float y) //添加当前点到目标点(x,y)构成的直线到path
rLineTo(float dx, float dy) //基于当前坐标系,即以path最后的那个点
//为坐标系原点(0,0),如果前面没有path的点,默认是屏幕左上角(0,0)

注:lineTo、rLineTo起始点默认是屏幕左上角的坐标系原点(0,0)

演示一下:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//屏幕左上角(0,0)到(200,200)画一条直线path.lineTo(200, 200);//(200, 200)到(200, 400)画一条直线path.lineTo(200, 400);//以(200, 400)为起始点(0,0)偏移量为(200, 400)画一条直线,//其终点坐标实际在屏幕的位置为(400, 800)path.rLineTo(400, 800);canvas.drawPath(path, paint);

结果:

点操作

moveTo(float x, float y) //改变接下来操作的起点位置为(x,y)
rMoveTo(float dx, float dy) //接下来要操作的起点位置为(x+dx,y+dy)
setLastPoint(float dx, float dy) //改变前一步操作点的位置,会改变前一步的操作

先对比一下moveTo()和rMoveTo()的区别,演示一下:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//将坐标系原点从(0,0)移动到(200,200)path.moveTo(200,200);//画从(200,200)到(400,400)之间的直线path.lineTo(400, 400);
//        path.rMoveTo(100, 0); //暂时注释path.lineTo(800, 400);canvas.drawPath(path, paint);

暂时注释了rMoveTo()方法,看看结果:

然后解掉rMoveTo()方法的注释,意思是下一步的起点位置由(400, 400)变为(400+100, 400+0),即(500,400),结果:

再来看看moveTo()和setLastPoint()的区别,同样以上的代码,加上path.setLastPoint(800, 200)方法:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//将坐标系原点从(0,0)移动到(200,200)path.moveTo(200,200);//画从(200,200)到(400,400)之间的直线path.lineTo(400, 400);path.setLastPoint(800, 200);path.lineTo(800, 400);canvas.drawPath(path, paint);

结果:

红线原本是设置setLastPoint(800, 200)之前的路径,在设置之后,影响到了前一步lineTo(400, 400)的操作,使之变成了lineTo(800, 200),结果就如图了。

得出结论: rMoveTo()影响的是后面操作的起点位置,并不会影响之前的操作;而setLastPoint()改变前一步操作最后一个点的位置,不仅影响前一步操作,同时也会影响后一步操作。

### 绘制常规图形

//绘制圆
addCircle(float x, float y, float radius, Direction dir) //绘制椭圆
addOval(RectF oval, Direction dir)
addOval(float left, float top, float right, float bottom, Direction dir)
//绘制矩形
addRect(RectF rect, Direction dir)
addRect(float left, float top, float right, float bottom, Direction dir)
//绘制圆角矩形
addRoundRect(RectF rect, float rx, float ry, Direction dir)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)
addRoundRect(RectF rect, float[] radii, Direction dir)
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)

所有API里面都有一个共同的参数Direction

Direction 备注
Path.Direction.CCW counter-clockwise ,沿逆时针方向绘制
Path.Direction.CW clockwise ,沿顺时针方向绘制

Direction其用法演示:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(2f);paint.setTextSize(40f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//以(600,600)为圆心,300为半径绘制圆//Path.Direction.CW顺时针绘制圆 Path.Direction.CCW逆时针绘制圆path.addCircle(600, 600, 300, Path.Direction.CCW);//沿path绘制文字canvas.drawTextOnPath("我是Layne,在测试Direction,这是CCW逆时针绘制圆", path, 0, 0, paint);canvas.drawPath(path, paint);

结果对比:

其他图形绘制示例:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(10f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//以(400,200)为圆心,半径为100绘制圆path.addCircle(550, 200, 100, Path.Direction.CW);//绘制椭圆RectF rectF = new RectF(100, 350, 500, 600);//第一种方法绘制椭圆path.addOval(rectF, Path.Direction.CW);//第二种方法绘制椭圆path.addOval(600, 350, 1000, 600, Path.Direction.CW);//绘制矩形RectF rect = new RectF(100, 650, 500, 900);//第一种方法绘制矩形path.addRect(rect, Path.Direction.CW);//第一种方法绘制矩形path.addRect(600, 650, 1000, 900, Path.Direction.CCW);//绘制圆角矩形RectF roundRect = new RectF(100, 950, 300, 1100);//第一种方法绘制圆角矩形path.addRoundRect(roundRect, 20, 20, Path.Direction.CW);//第二种方法绘制圆角矩形path.addRoundRect(350, 950, 550, 1100, 10, 50, Path.Direction.CCW);//第三种方法绘制圆角矩形//float[] radii中有8个值,依次为左上角,右上角,右下角,左下角的rx,ryRectF roundRectT = new RectF(600, 950, 800, 1100);path.addRoundRect(roundRectT, new float[]{50, 50, 50, 50, 50, 50, 0, 0}, Path.Direction.CCW);//第四种方法绘制圆角矩形path.addRoundRect(850, 950, 1050, 1100,new float[]{0, 0, 0, 0,50, 50, 50, 50}, Path.Direction.CCW);canvas.drawPath(path, paint);

结果:

### 绘制圆弧

//绘制圆弧
addArc(RectF oval, float startAngle, float sweepAngle)
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle)//forceMoveTo:是否强制将path最后一个点移动到圆弧起点,
//true是强制移动,即为不连接两个点;false则连接两个点
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)
arcTo(RectF oval, float startAngle, float sweepAngle)
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

addArc()和arcTo()都是添加圆弧到path中,不过他们之间还是有区别的。addArc()是直接添加圆弧到path中;而arcTo()会判断要绘制圆弧的起点与绘制圆弧之前path中最后的点是否是同一个点,如果不是同一个点的话,就会连接两个点。

演示一下:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(20f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//在F(400, 200, 700, 500)区域内绘制一个270度的圆弧RectF rectF = new RectF(400, 200, 700, 500);path.addArc(rectF, 0, 270);//在(400, 600, 600, 800)区域内绘制一个90度的圆弧,并且不连接两个点RectF rectFTo = new RectF(400, 600, 700, 900);path.arcTo(rectFTo, 0, 180, true); //等价于path.addArc(rectFTo, 0, 180);canvas.drawPath(path, paint);

结果:

把上面代码修改成连接两点:

path.arcTo(rectFTo, 0, 180, false); //等价于path.addArc(rectFTo, 0, 180);

结果:

闭合path操作

如果path的重点和起始点不是同一个点的话,那么path.close()就会连接这两个点,形成一个封闭的图形。演示一下:

        Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE); //只描边paint.setColor(Color.BLUE);paint.setStrokeWidth(20f);paint.setAntiAlias(true); //设置抗锯齿paint.setDither(true); //设置防抖动Path path = new Path();//在F(400, 200, 700, 500)区域内绘制一个270度的圆弧RectF rectF = new RectF(400, 200, 700, 500);path.addArc(rectF, 0, 270);//        path.close(); //先注释canvas.drawPath(path, paint);

结果:

接下来解掉path.close()的注释,再运行一次,结果:

贝塞尔曲线

贝塞尔曲线就麻烦多了,也复杂多了。这里不详细说明了,再网上找到一篇说明比较详细的文章。
安卓自定义View进阶 - 贝塞尔曲线

这里直接复制了里面的二阶曲线的实现:

public class CanvasView extends View {private Paint mPaint;private int centerX, centerY;private PointF start, end, control;public CanvasView(Context context, @Nullable 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);control = new PointF(0, 0);}@Overrideprotected 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;control.x = centerX;control.y = centerY - 100;}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 根据触摸位置更新控制点,并提示重绘control.x = event.getX();control.y = event.getY();invalidate();//刷新View,重新绘制return true;}@Overrideprotected 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(control.x, control.y, mPaint);// 绘制辅助线mPaint.setStrokeWidth(4);canvas.drawLine(start.x, start.y, control.x, control.y, mPaint);canvas.drawLine(end.x, end.y, control.x, control.y, mPaint);// 绘制贝塞尔曲线mPaint.setColor(Color.RED);mPaint.setStrokeWidth(8);Path path = new Path();path.moveTo(start.x, start.y);path.quadTo(control.x, control.y, end.x, end.y);canvas.drawPath(path, mPaint);}
}

结果:

关注个人公众号「技术人的日常」,关注后回复:安卓基础,即可获取Android基础入门学习资料。

参考资料:[https://www.jianshu.com/p/9ad3aaae0c63](https://www.jianshu.com/p/9ad3aaae0c63)

自定义View中Canvas之Path的详解相关推荐

  1. 安卓自定义view系列之paint画笔类详解

    /** * Paint类介绍 * * Paint即画笔,在绘图过程中起到了极其重要的作用,画笔主要保存了颜色, * 样式等绘制信息,指定了如何绘制文本和图形,画笔对象有很多设置方法, * 大体上可以分 ...

  2. Android Canvas之Path的详解与使用(二)

    Path: Path类封装复合(多轮廓)几何路径由直线段.二次曲线和三次曲线组成.它可以用画布绘制.drawPath(路径.绘制),填充或笔划(基于绘画的样式),或者可以用于剪裁或绘制路径上的文本. ...

  3. android跑马灯效果横向,Android自定义View实现纵向跑马灯效果详解

    首先看看效果图(录制的gif有点卡,真实的效果还是很流畅的) 实现思路 通过上面的gif图可以得出结论,其实它就是同时绘制两条文本信息,然后通过动画不断的改变两条文本信息距离顶部的高度,以此来实现滚动 ...

  4. 自定义View之Canvas(画布)的详解

    接下来学习一下自定义View之Canvas(画布)的详解 先来看看Canvas常用方法: 功能分类 Canvas常用方法 备注 绘制颜色 drawARGB 通过设置ARGB值绘制颜色 drawRGB ...

  5. 安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例

    安卓自定义view中 绘画基本图形点线面,矩形,方形,圆,扇形,文字及沿着特定方向布局,自定义圆角ImageView图片等等相关api使用方法及举例,图片压缩处理逻辑 本文旨在介绍自定义View的实现 ...

  6. Android自定义View之Canvas绘制基本图形(二)-- 自定义时钟

    前言 前面一篇主要是巩固Cavas绘制基本图形(如直线,矩形,点等等),今天同样是复习Cavas画圆,圆弧,等等,但是今天会多了一个path,以及Canvas画布的旋转.缩放.平移等等,画布的保存(s ...

  7. Android 自定义View中坐标点的理解学习(一)

    本文主要是记录学习自定义view中看到的资料,为了方便记忆做了保存整理便于自己学习也方便其他Android开发爱好者学习,参考资料看底部链接. 一.getLocationInWindow和getLoc ...

  8. c语言自定义color,forecolor c语言中的颜色设置语句详解

    backcolor与forecolor的区别 backcolor:用来设置图像的背景颜色,也用来设置文档.表格.图像等的背景颜色. forecolor:用来设置图像的前景颜色,也用来设置文档.表格.图 ...

  9. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  10. iOS中的HotFix方案总结详解

    iOS中的HotFix方案总结详解 相信HotFix大家应该都很熟悉了,今天主要对于最近调研的一些方案做一些总结.iOS中的HotFix方案大致可以分为四种: WaxPatch(Alibaba) Dy ...

最新文章

  1. .NET : 再谈谈多线程
  2. wxWidgets:wxDCClipper类用法
  3. rndis ethernet gadget 驱动 安装方法
  4. 前端:40 个 CSS 布局技巧
  5. BugkuCTF-MISC题Pokergame
  6. 左侧固定 右侧自适应三种方法
  7. RTSP播放器开发过程中需要考虑哪些关键因素
  8. postman跨域测试_安装使用Hoppscotch构建API请求访问与测试
  9. 在Visual Studio中使用GitHub(使用篇)
  10. PyCharm免费版安装使用
  11. 动易cms聚合空间最近访客访问地址错误解决方法
  12. 劲舞团显示正在登录message 服务器,[新手]劲舞团2.0之表情和message系统
  13. FYI | OHBM/Brain 会议投稿指北
  14. Visual studio2022 利用glfw+glad配置OpenGL环境
  15. vue音乐播放器笔记
  16. win10服务器网页打不开怎么办,win10系统浏览器网页打不开的解决技巧
  17. 75道经典AI面试题,我就想把你们安排的明明白白的!(含答案)
  18. 使用Qt开发中国象棋(六):将军和死棋检测
  19. Android6.0 MTK 需求文档(六)
  20. 微信支付与微信转账的区别

热门文章

  1. 安装免费在线客服livezilla系统
  2. 用JS逐步分解实现放大镜(看完就有收获)
  3. 设计符合人需求层次模型的商业模式——揭密冰桶挑战背后,不为人知的商业秘密!
  4. 关于android百度导航不能出声音的解决办法
  5. linux u盘 驱动怎么安装步骤,怎样利用U盘加载控制器驱动安装Linux系统?
  6. 软件测试中的黑盒与白盒测试
  7. PMP项目管理-项目成本管理(3)
  8. 读《创业36条军规》(六)凡事只能靠自己
  9. css Flex布局第一部分(基础)
  10. Hadoop培训视频教程