如何利用Flutter的CustomPainter组件优化线条绘制?
优化CustomPainter点列表:移除直线冗余点
核心思路是只保留折线的拐点,忽略同一直线上的中间点,既能保证绘制效果准确,又能大幅减少点的数量,解决性能问题。
关键算法:判断三点共线
用叉积判断三点是否共线,设置小阈值避免浮点精度误差:
bool areCollinear(Offset p1, Offset p2, Offset p3, {double tolerance = 1e-6}) { // 叉积为0时三点共线 final crossProduct = (p2.dy - p1.dy) * (p3.dx - p2.dx) - (p3.dy - p2.dy) * (p2.dx - p1.dx); return crossProduct.abs() < tolerance; }
基础版点列表维护逻辑
适配连续单向/反向移动场景,只检查最后两个点与新点的共线性:
void cursorChange(Offset newPoint) { // 跳过重复点 if (points.isNotEmpty && points.last == newPoint) return; if (points.length < 2) { // 不足两个点时直接添加 points.add(newPoint); } else { final prevPrev = points[points.length - 2]; final prev = points.last; if (areCollinear(prevPrev, prev, newPoint)) { // 共线则替换最后一个点,只保留线段两端 points ..removeLast() ..add(newPoint); } else { // 不共线则添加新拐点 points.add(newPoint); } } setState(() {}); }
解决你的具体问题:
- 反向移动:比如从B回到A、B之间的点C,由于C与A、B共线,代码会把B替换成C,点列表变为
[A,C],不会删除初始点A,线条长度随移动实时更新。 - 垂直旋转:新点与最后两个点不共线,会被添加为新拐点,线条会正确呈现折线效果,不会直接跳转到新位置。
进阶版:处理多段连续共线
如果用户多次切换方向后又回到同一直线(比如A→B→C→D四点共线),可以扩展逻辑一次性简化所有中间点:
void cursorChange(Offset newPoint) { if (points.isNotEmpty && points.last == newPoint) return; if (points.length < 2) { points.add(newPoint); } else { // 从后往前找到第一个与新点不共线的点 int keepIndex = points.length - 1; for (int i = points.length - 2; i >= 0; i--) { if (!areCollinear(points[i], points[keepIndex], newPoint)) { break; } keepIndex = i; } // 移除中间冗余点并添加新点 points.removeRange(keepIndex + 1, points.length); points.add(newPoint); } setState(() {}); }
这个版本会把连续共线的点直接简化为两端点,进一步压缩点数量,性能更优。
内容的提问来源于stack exchange,提问作者Slavy
相关产品推荐
相关产品推荐

