You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何利用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(() {});
}

解决你的具体问题:

  1. 反向移动:比如从B回到A、B之间的点C,由于C与A、B共线,代码会把B替换成C,点列表变为[A,C],不会删除初始点A,线条长度随移动实时更新。
  2. 垂直旋转:新点与最后两个点不共线,会被添加为新拐点,线条会正确呈现折线效果,不会直接跳转到新位置。

进阶版:处理多段连续共线

如果用户多次切换方向后又回到同一直线(比如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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 06:21:37