Flutter中如何对Path执行inflate/deflate操作?
实现Canvas Path的膨胀(Inflate)与收缩(Deflate)
Path本身没有像Rect那样现成的inflate/deflate方法,但咱们可以通过路径采样+法线偏移的方式自己实现,原理很简单:沿着路径的法线方向,把路径上的每个点往外(膨胀)或往里(收缩)偏移指定距离,再用这些偏移后的点重新构建新路径。
原生代码实现
给Path写个扩展方法,直接调用就能实现膨胀/收缩,正数是膨胀,负数是收缩:
import 'dart:math'; import 'package:flutter/material.dart'; extension PathInflate on Path { Path inflate(double distance) { final newPath = Path(); final pathMetrics = computeMetrics(); for (final metric in pathMetrics) { final totalLength = metric.length; const sampleStep = 2.0; // 采样步长,越小越平滑但越费性能,按需调整 var currentOffset = 0.0; final sampledPoints = <Offset>[]; while (currentOffset <= totalLength) { final tangent = metric.getTangentForOffset(currentOffset)!; // 计算法线方向:切线转90度后归一化,再乘以偏移距离 final normal = Offset(-tangent.direction.dy, tangent.direction.dx) .normalized * distance; sampledPoints.add(tangent.position + normal); currentOffset += sampleStep; } // 用采样点拼接新路径 if (sampledPoints.isNotEmpty) { newPath.moveTo(sampledPoints.first.dx, sampledPoints.first.dy); for (var i = 1; i < sampledPoints.length; i++) { newPath.lineTo(sampledPoints[i].dx, sampledPoints[i].dy); } // 原路径闭合的话,新路径也自动闭合 if (metric.isClosed) { newPath.close(); } } } return newPath; } }
使用示例
举个实际绘制的例子:
// 定义原始自定义路径 final originalPath = Path() ..moveTo(50, 50) ..lineTo(200, 50) ..quadraticBezierTo(250, 100, 200, 150) ..lineTo(50, 150) ..close(); // 膨胀10像素 final inflatedPath = originalPath.inflate(10); // 收缩5像素 final deflatedPath = originalPath.inflate(-5); // 在Canvas上渲染路径 @override void paint(Canvas canvas, Size size) { // 原始路径(黑色实线) canvas.drawPath(originalPath, Paint()..color = Colors.black..strokeWidth = 2..style = PaintingStyle.stroke); // 膨胀后的路径(红色描边) canvas.drawPath(inflatedPath, Paint()..color = Colors.red..strokeWidth = 2..style = PaintingStyle.stroke..strokeJoin = StrokeJoin.round); // 收缩后的路径(蓝色描边) canvas.drawPath(deflatedPath, Paint()..color = Colors.blue..strokeWidth = 2..style = PaintingStyle.stroke..strokeJoin = StrokeJoin.round); }
注意事项
- 采样步长:步长越小,生成的偏移路径越平滑,但计算开销会增加,根据路径复杂度自行调整。
- 复杂曲线:如果路径包含大量曲线段,缩小采样步长能保证偏移后的曲线更贴近原路径形状。
- 边界情况:收缩距离不宜过大,否则可能导致路径自相交甚至完全消失,需根据实际场景做边界判断。
替代方案:第三方库
如果需要处理特别复杂的路径,或者想要更精确的偏移效果,可以使用flutter_path_operations库,它提供了专业的路径偏移、布尔运算等高级功能,比手动采样的实现更可靠。
内容的提问来源于stack exchange,提问作者BambinoUA
相关产品推荐
相关产品推荐

