Flutter学习:使用CustomPaint绘制路径
Flutter学习:认识CustomPaint组件和Paint对象
Flutter学习:使用CustomPaint绘制路径
Flutter学习:使用CustomPaint绘制图形
Flutter学习:使用CustomPaint绘制文字
Flutter学习:使用CustomPaint绘制图片
drawPath 绘制路径
drawPath需要传递2个参数:
- Path path 路径对象
- Paint paint 绘制对象
dart
复制代码
Path path = Path()..moveTo(100, 100); path.lineTo(250, 250); path.lineTo(350, 180); path.lineTo(200, 500); // 控制路径是否闭合,可不写 path.close(); canvas.drawPath(path, paint);
path.moveTo和path.lineTo
path.moveTo和path.lineTo一样,都需要传递2个参数:
- double x用来设置点的横坐标(x轴)
- double y用来设置点的纵坐标(y轴)
dart
复制代码
path.moveTo(80, 200); path.lineTo(320, 400); canvas.drawPath(path, paint);
其中p0是path.moveTo设置的坐标,p1是path.lineTo设置的坐标
path.relativeMoveTo和path.relativeLineTo
path.relativeMoveTo和path.relativeLineTofiType的使用方法和path.moveTo、path.lineTo一样,只是起始点不再是左上角,而是前一个点的坐标
path.close
用来设置路径是否自己闭合:
dart
复制代码
path.close();
path.reset
清除之前所有的Path对象。并重置原点为左上角。
dart
复制代码
path.reset();
path.fillType
关于fillType的资料可以查看以下文章:
- Quartz2D的渲染模式
fillType有两个枚举值:
- PathFillType.nonZero:内部由有符号边缘交叉的非零和定义。对于给定点,如果从该点到无穷远的线与绕该点顺时针方向的线交叉的次数与与绕该点逆时针方向的线交叉的次数不同,则认为该点位于路径的内侧。
- PathFillType.evenOdd:内部由奇数个边缘交叉定义。对于给定点,如果从该点到无穷远的线穿过奇数条线,则认为该点位于路径的内侧
dart
复制代码
Path path = Path()..moveTo(size.width / 2, 200); path.lineTo(size.width / 4, 500); path.lineTo(size.width / 7 * 6, 320); path.lineTo(size.width / 7, 320); path.lineTo(size.width / 4 * 3, 500); path.close(); // 默认值 path.fillType = PathFillType.nonZero; path.fillType = PathFillType.evenOdd; canvas.drawPath(path, paint);
path.addArc
通过路径绘制圆弧
addArc(Rect oval, double startAngle, double sweepAngle)
需要传递3个参数:
- oval绘制一个矩形
- startAngle圆弧开始处
- sweepAngle圆弧开始到结束的角度大小
dart
复制代码
// 只有path.addArc方法,path.moveTo方法将会无效 Path path = Path(); // path.moveTo(size.width / 2, 200); 无效 Rect oval = Rect.fromPoints(const Offset(80, 80), const Offset(300, 180)); path.addArc(oval, 0, 4); canvas.drawPath(path, paint);
dart
复制代码
// 有path.moveTo、path.lineTo、path.addArc这3个方法 // path.lineTo在谁的后面就跟谁连接,默认path.moveTo为(0,0) Path path = Path(); path.moveTo(size.width / 2, 200); Rect oval = Rect.fromPoints(const Offset(80, 80), const Offset(300, 180)); path.addArc(oval, 0, 4); path.lineTo(250, 400); canvas.drawPath(path, paint);
path.addOval、path.addRect、path.addRRect用法和path.addArc一样
path.addPath
该方法将复制一遍已绘制的路径,并进行偏移
addPath(Path path, Offset offset, {Float64List? matrix4})
可以传递3个参数,2个必要的,一个可选的:
- path已绘制的路径对象
- offset对path对象进行的偏移量
- matrix4将矩阵平移给定偏移量
没有使用matrix4属性:
dart
复制代码
Path path = Path()..moveTo(100, 100); path.lineTo(210, 240); path.lineTo(80, 380); path.addPath(path, const Offset(120, 120)); canvas.drawPath(path, paint);
使用了matrix4属性:
dart
复制代码
Path path = Path()..moveTo(100, 100); path.lineTo(210, 240); path.lineTo(80, 380); // 变形(倾斜)路径 path.addPath(path, const Offset(120, 120), matrix4: Matrix4.skew(.1, .1).storage); canvas.drawPath(path, paint);
path.extendWithPath
效果和path.addPath一样,属性也一样,只是该方法会将这两条线段连接起来:
dart
复制代码
Path path = Path()..moveTo(100, 100); path.lineTo(210, 240); path.lineTo(80, 380); path.extendWithPath(path, const Offset(120, 120), matrix4: Matrix4.skew(.2, .4).storage); canvas.drawPath(path, paint);
path.addPolygon
添加一条新路径
addPolygon(List points, bool close)
需要传递2个参数:
- points一系列点的坐标
- close是否首位相连
dart
复制代码
path.moveTo(size.width / 2, 200); path.lineTo(200, 380); path.lineTo(80, 460); List<Offset> points = const [ Offset(100, 40), Offset(350, 240), Offset(200, 500), ]; path.addPolygon(points, true); canvas.drawPath(path, paint);
path.arcTo
绘制圆弧路径
arcTo( Rect rect, double startAngle, double sweepAngle, bool forceMoveTo, )
需要传递4个参数:
- rect绘制一个矩形用来确定圆弧的位置
- startAngle圆弧开始的角度
- sweepAngle圆弧开始到结束的角度大小
- forceMoveTo圆弧路径为新路径还是与原路径相连
dart
复制代码
path.moveTo(size.width / 2, 200); path.lineTo(80, 460); Rect rect = Rect.fromPoints(const Offset(80, 340), const Offset(280, 420)); // forceMoveTo为true path.arcTo(rect, 0, 5, true); // forceMoveTo为false path.arcTo(rect, 0, 5, false); canvas.drawPath(path, paint);
path.arcToPoint
绘制一个两点之间线段距离的直径圆弧
arcToPoint(Offset arcEnd, {Radius radius = Radius.zero, double rotation = 0.0, bool largeArc = false, bool clockwise = true})
可以传递5个参数,1个必要的,4个可选的:
- arcEnd确定圆弧的结束点坐标
- radius为0时将绘制一条直线
- rotation感觉没啥用
- largeArc是否是大圆弧
- clockwise决定圆弧的绘制是从左边还是右边
dart
复制代码
path.moveTo(100, 200); // p0 path.arcToPoint( const Offset(320, 500), radius: const Radius.circular(.5), rotation: 2, argeArc: true, clockwise: false, ); // p1 path.arcToPoint( onst Offset(160, 250), adius: const Radius.circular(1), otation: 0, argeArc: true, lockwise: false, ); // p2 path.arcToPoint( const Offset(240, 375), radius: const Radius.circular(0), rotation: 5, largeArc: false, clockwise: true, ); canvas.drawPath(path, paint);
path.relativeArcToPoint
效果和path.arcToPoint一样,只是起始点为前一个点
path.conicTo
绘制圆锥路径
conicTo(double x1, double y1, double x2, double y2, double w)
需要传递5个参数:
- x1是第一个点x轴的坐标
- y1是第一个点y轴的坐标
- x2是第二个点x轴的坐标
- y2是第二个点y轴的坐标
- w是权重值。如果权重大于1,则曲线为双曲线;如果权重等于 1,则为抛物线;如果小于 1,则为椭圆
dart
复制代码
path.moveTo(size.width / 2, 200); // 权重=0 path.conicTo(80, 280, 300, 380, 0); // 权重=1 path.conicTo(80, 280, 300, 380, 1); // 权重=2 path.conicTo(80, 280, 300, 380, 2); canvas.drawPath(path, paint);
path.relativeConicTo
效果和path.conicTo一样,只是起始点为前一个点
path.quadraticBezierTo
使用控制点 (x1,y1) 添加一个从当前点弯曲到给定点 (x2,y2) 的二次贝塞尔曲线段
quadraticBezierTo( double x1, double y1, double x2, double y2)
需要传递4个参数:
- x1是第一个点x轴的坐标
- y1是第一个点y轴的坐标
- x2是第二个点x轴的坐标
- y2是第二个点y轴的坐标
dart
复制代码
path.moveTo(20, 200); path.quadraticBezierTo(200, 80, size.width - 20, size.width); canvas.drawPath(path, paint);
其中p0代表起始点位置(path.moveTo(20, 200)),p1的坐标是**(x1, y1),p2的坐标是(x2, y2)**
path.relativeQuadraticBezierTo
效果和path.quadraticBezierTo一样,只是起始点为前一个点
path.cubicTo
使用控制点 (x1,y1) 和 (x2,y2) 添加从当前点弯曲到给定点 (x3,y3) 的三次贝塞尔曲线段
cubicTo( double x1, double y1, double x2, double y2, double x3, double y3)
需要传递6个参数:
- x1是第一个点x轴的坐标
- y1是第一个点y轴的坐标
- x2是第二个点x轴的坐标
- y2是第二个点y轴的坐标
- x3是第三个点x轴的坐标
- y3是第三个点y轴的坐标
dart
复制代码
path.moveTo(100, 200); path.cubicTo(120, 120, 240, 360, 310, 360); canvas.drawPath(path, paint);
其中p1代表p0点控制线的右边坐标,p2代表p3点控制线的左边坐标
path.relativeCubicTo
效果和path.cubicTo一样,只是起始点为前一个点
path.transform
复制线段,并对其路径进行变形。transform(Float64List matrix4)
需要传递一个Float64List对象:
绘制第一条线段:
dart
复制代码
Paint paint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 8 ..color = Colors.red; Path path = Path(); path.moveTo(80, 100); path.lineTo(140, 200); path.lineTo(320, 280); path.lineTo(100, 400); canvas.drawPath(path, paint);
绘制第二条线段:
dart
复制代码
Paint paint1 = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 8 ..color = Colors.blue; Path path1 = path.transform(Matrix4.skew(.1, .4).storage); canvas.drawPath(path1, paint1);
path.getBounds
获取路径的边界矩形
dart
复制代码
path.moveTo(50, 200); path.lineTo(300, 280); // path.getBounds()的结果为Rect.fromLTRB(50.0, 200.0, 300.0, 280.0) print(path.getBounds()); canvas.drawPath(path, paint);
path.shift
功能和path.add一样,只不过不会自动绘制一份路径,会把路径复制一份然后赋值给其他路径。
- Offset offset,复制一份路径后设置偏移量
第一条路径:
dart
复制代码
Paint paint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 8 ..color = Colors.red; Path path = Path(); path.moveTo(size.width / 2, 200); path.lineTo(80, 450); path.lineTo(size.width - 80, 450); path.close(); canvas.drawPath(path, paint);
复制第一条路径,并偏移:
dart
复制代码
Paint paint1 = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 8 ..color = Colors.blue; Path path1 = path.shift(const Offset(50, 50)); canvas.drawPath(path1, paint1);
path.contains
测试给定点是否在路径内。也就是说,如果路径与Canvas.clipPath一起使用,该点是否位于路径的可见部分。
- Offset point,设置要检测的点的位置
dart
复制代码
Offset point1 = const Offset(200, 320); print(path.contains(point1)); Offset point2 = const Offset(200, 520); print(path.contains(point2));
如果该点在路径内,就返回 true,否则返回 false。
path.computeMetrics
path.computeMetrics可以获取路径的详细信息。
computeMetrics({bool forceClosed = false})
有一个可选参数:
- forceClosed,如果没有使用
path.close();
,该方法获取的结果isClose将会为false。设置该值为true,isClose将会为true
我们先绘制一条普通路径:
dart
复制代码
Paint paint = Paint() ..style = PaintingStyle.stroke ..strokeWidth = 8 ..color = Colors.red; Path path = Path(); path.moveTo(size.width / 2, 200); path.lineTo(80, 450); path.lineTo(size.width - 80, 450); path.close();
如果直接对以上绘制的路径使用path.computeMetrics
,会返回一个PathMetrics
对象:
dart
复制代码
PathMetrics pathMetrics = path.computeMetrics();
一般我们需要用到的是PathMetric
对象,获取该对象一共有以下几种方法:
dart
复制代码
// 如果只有一个PathMetric对象推荐使用该方法 PathMetric pathMetric = pathMetrics.single; // 如果有很多个PathMetric对象使用以下任意方法 PathMetric pathMetric = pathMetrics.elementAt(0); PathMetric pathMetric = pathMetrics.first; PathMetric pathMetric = pathMetrics.last;
获取到PathMetric
对象后,我们就可以沿着这条路径绘制一条新的路径,使用extractPath方法。
该方法可以传递3个参数:
double start
:给定线段开始的距离double end
:给定线段结束的距离bool startWithMoveTo
:是否以 moveTo 点开始绘制线段
dart
复制代码
Path path1 = pathMetric.extractPath(50, 400, startWithMoveTo: true);
dart
复制代码
Path path1 = pathMetric.extractPath(50, 400, startWithMoveTo: false);
关于computeMetrics的方法和属性还有很多没讲到,等以后有时间了再慢慢研究。
作者:菠萝橙子丶
链接:https://juejin.cn/post/7083304661645541390
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
相关文章:

Flutter学习:使用CustomPaint绘制路径
Flutter学习:认识CustomPaint组件和Paint对象 Flutter学习:使用CustomPaint绘制路径 Flutter学习:使用CustomPaint绘制图形 Flutter学习:使用CustomPaint绘制文字 Flutter学习:使用CustomPaint绘制图片 drawPath 绘制路…...

软件模拟SPI协议的理解和使用编写W25Q64
SPI软件模拟的时序 SPI协议中,NSS、SCK、MOSI由主机产生,MISO由从机产生,在SCK每个时钟周期MOSI、MISO传输一位数据,数据的输入输出是同时进行的,所以读写数据也可以视作交换数据。所以读写时对数据位的控制都是用同一…...
SQLI手动注入和python sqlmap代码注入
sql教程: https://www.w3school.com.cn/sql/index.asp数据库: mysql oracle mssql常用方法 system_user() 系统用户名 user() 用户名 current_user() 当前用户名 session_user() 连接数据库的用户名 d…...

MemcachedRedis构建缓存服务器 (数据持久化,主从同步,哨兵模式)
Memcached/redis是高性能的分布式内存缓存服务器,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web等应用的速度、 提高可扩展性。降低数据库读的压力 Nsql的优点:高可扩展性,分布式计算,低成本,…...

Python语法基础(变量 注释 数据类型 输入与输出 运算符 缩进)
目录 变量变量命名规则变量的类型变量的创建变量的作用域 注释的方法数据类型对象和引用的概念Number(数字)数据转换 输入与输出输入函数输出函数输出函数的end参数输出格式多行语句 运算符算术运算符赋值运算符三目运算符运算符的优先级 缩进缩进格式注意事项层级嵌套 变量 标…...

linux espeak语音tts;pyttsx3 ubuntu使用
整体使用espeak声音很机械不太自然 1、linux espeak语音tts 安装: sudo apt install espeak使用: #中文男声 espeak -v zh 你好 #中文女声 espeak -v zhf3 你好 #粤语男声 espeak -v zhy 你好注意:espeak -v zh 你好 (Full d…...

小白该如何学习Linux操作系统?
💂 个人网站:【工具大全】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 Linux作为一种开源操作系…...

2023双十一:实体门店闯入,第二战场全面开战
“闺女,吃饺子了吗?”11月8日,立冬,忙碌一天的陈曦回家路上接到母亲电话,才想起来家里冷冻水饺没了,又不想再去超市,直接打开美团买菜买了两袋,回家就煮了吃。当然,最终她…...

操作系统·处理机调度死锁
3.1 处理机调度概述 3.1.1 处理机调度概述 高级调度 (High level Scheduling)决定把外存上哪些作业调入内存、创建进程、分配资源。高级调度又称作业调度、长程调度或宏观调度。只在批处理系统中有高级调度。 中级调度 (Middle level Scheduling)完成进程的部分或全部在内、…...

SQL第四次上机实验
1.查询借阅了计算机类或者文学类图书的读者的借书证号 USE TSGL GO SELECT DISTINCT Reader.Lno FROM Book,Lend,Reader WHERE Book.ISBNLend.ISBN AND Lend.LnoReader.Lno AND Class 计算机类 OR Class 文学类2.查询同时借阅了计算机类和文学类图书的读者的借书证号 USE T…...
读书笔记:彼得·德鲁克《认识管理》第11章 若干例外及经验教训
一、章节内容概述 例外的服务机构不仅表明服务机构实现卓越绩效不是天方夜谭,而 且指明了实现的方法。这一课,是美国电话电报公司给“自然垄断行业”上的;是19世纪后期处于创建阶段的美国现代大学给学校或医院类机构上的;是20世纪30年代的田纳西河流域管…...

JVM-虚拟机的故障处理与调优案例分析
案例1:大内存硬件上的程序部署策略 一个15万PV/日左右的在线文档类型网站最近更换了硬件系统,服务器的硬件为四路志强处理器、16GB物理内存,操作系统为64位CentOS 5.4,Resin作为Web服务器。整个服务器暂时没有部署别的应用&#…...

JMeter 相关的面试题
📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢交流讨论:加入1000人软件测试技术学习交流群📢资源分享:进了字节跳动之后,才…...

你在React项目中是如何使用Redux的? 项目结构是如何划分的?
一、背景 在前面文章了解中,我们了解到redux是用于数据状态管理,而react是一个视图层面的库 如果将两者连接在一起,可以使用官方推荐react-redux库,其具有高效且灵活的特性 react-redux将组件分成: 容器组件&#…...

[每周一更]-(第71期):DevOps 是什么?
Wiki的解释: DevOps(Development和Operations的混成词)是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。 通过自动化“软件交付”和“架构变更”的…...

k8s的安装部署,详细过程展示(保姆级安装教程)
k8s应用部署方式演变 在部署应用程序的方式上,主要经历了三个时代: 传统部署:互联网早期,会直接将应用程序部署在物理机上 优点:简单,不需要其它技术的参与 缺点:不能为应用程序定义资源使用…...
基于windows、GDAL2.2.3版本和Java集成安装和使用GDAL库的方法
基于windows、GDAL2.2.3版本和Java集成安装和使用GDAL库的方法 一、下载gdal windows版本64位2.2.3版本 下载地址: https://www.gisinternals.com/archive.php 找到gdal-202-1911-x64-core.msi下载并安装 安装后默认目录为:C:\Program Files\GDAL 二、…...

AlphaControls控件TsRadioGroup的使用
通常使用AlphaControls控件中的TsRadioGroup时,往往使用默认值,会造成TsRadioGroup标题被TsRadioGroup的ITEMs占用,严重影响美观: 解决方案,通过对TsRadioGroup的ContentVOffset属性,设置为10。即可立即改善…...
安卓常见设计模式8------享元模式(Kotlin版)
1. W1 是什么,什么是享元模式? 享元模式(Flyweight Pattern)是一种结构型设计模式,用于有效地支持大量细粒度的对象共享。在 Android 中,享元模式可以用于减少内存使用和提高性能,特别是在需…...
day54 django中orm数据库增删改查
昨日内容回顾 三板斧问题 HttpResponse # 返回的是字符串 render # 渲染一个HTML静态文件,模板文件 redirect # 重定向的 """在视图文件中得视图函数必须要接收一个形参request,并且,视图…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...