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

使用Flutter Custom Painter实现绘制路径(Path)的边角圆润处理

Flutter Custom Painter 路径圆角处理方案

下面提供针对自定义路径的圆角实现方法,适用于不规则折线组成的路径:

核心思路

遍历路径的每个线段拐角,计算合适的圆弧替换尖角,在保留路径原有形状的同时实现圆润边角。

代码实现

1. 路径圆角处理工具函数

Path addCornersToPath(Path originalPath, double radius) {
  final pathMetrics = originalPath.computeMetrics();
  final roundedPath = Path();

  for (final metric in pathMetrics) {
    final path = metric.extractPath(0, metric.length);
    final iterator = path.iterator;
    var previousPoint = Offset.zero;
    var currentPoint = Offset.zero;
    var nextPoint = Offset.zero;
    var isFirstMove = true;

    while (iterator.moveNext()) {
      currentPoint = iterator.current;
      if (iterator.currentSegment == PathSegment.moveTo) {
        roundedPath.moveTo(currentPoint.dx, currentPoint.dy);
        previousPoint = currentPoint;
        isFirstMove = false;
      } else if (iterator.currentSegment == PathSegment.lineTo) {
        if (iterator.moveNext()) {
          nextPoint = iterator.current;
          // 计算拐角圆弧参数并添加到新路径
          final cornerData = _calculateCornerArc(previousPoint, currentPoint, nextPoint, radius);
          roundedPath.addArc(cornerData.rect, cornerData.startAngle, cornerData.sweepAngle);
          // 回退迭代,保留nextPoint作为下一轮的currentPoint
          iterator.movePrevious();
          previousPoint = currentPoint;
        } else {
          // 处理最后一段线段,直接连接到终点
          roundedPath.lineTo(currentPoint.dx, currentPoint.dy);
        }
      }
    }
  }

  roundedPath.close();
  return roundedPath;
}

// 计算拐角处的圆弧参数
({Rect rect, double startAngle, double sweepAngle}) _calculateCornerArc(Offset prev, Offset curr, Offset next, double radius) {
  // 计算两条线段的方向向量
  final v1 = prev - curr;
  final v2 = next - curr;

  // 判断拐角方向(顺时针/逆时针)
  final isClockwise = (v1.dx * v2.dy - v1.dy * v2.dx) > 0;

  // 计算两条线段的单位向量
  final unitV1 = v1.normalized;
  final unitV2 = v2.normalized;

  // 计算圆弧圆心
  final bisector = (unitV1 + unitV2).normalized;
  final distance = radius / sin((pi - v1.angleTo(v2)) / 2);
  final center = curr + bisector * distance * (isClockwise ? -1 : 1);

  // 计算圆弧的起始和结束角度
  final startAngle = (prev - center).direction;
  final endAngle = (next - center).direction;

  // 计算扫过的角度,确保方向正确
  var sweepAngle = endAngle - startAngle;
  if (isClockwise && sweepAngle > 0) sweepAngle -= 2 * pi;
  if (!isClockwise && sweepAngle < 0) sweepAngle += 2 * pi;

  return (
    rect: Rect.fromCircle(center: center, radius: radius),
    startAngle: startAngle,
    sweepAngle: sweepAngle
  );
}

2. 自定义Painter使用示例

class RoundedPathPainter extends CustomPainter {
  final double cornerRadius;

  RoundedPathPainter({this.cornerRadius = 16.0});

  @override
  void paint(Canvas canvas, Size size) {
    // 模拟你的原始不规则路径
    final originalPath = Path()
      ..moveTo(size.width * 0.2, size.height * 0.2)
      ..lineTo(size.width * 0.8, size.height * 0.2)
      ..lineTo(size.width * 0.9, size.height * 0.5)
      ..lineTo(size.width * 0.7, size.height * 0.8)
      ..lineTo(size.width * 0.3, size.height * 0.8)
      ..lineTo(size.width * 0.1, size.height * 0.5);

    // 生成带圆角的路径
    final roundedPath = addCornersToPath(originalPath, cornerRadius);

    // 绘制填充路径
    final fillPaint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;
    canvas.drawPath(roundedPath, fillPaint);

    // 可选:绘制原始路径对比(半透明红色描边)
    final strokePaint = Paint()
      ..color = Colors.red.withOpacity(0.5)
      ..style = PaintingStyle.stroke
      ..strokeWidth = 2;
    canvas.drawPath(originalPath, strokePaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return oldDelegate is RoundedPathPainter && oldDelegate.cornerRadius != cornerRadius;
  }
}

注意事项

  • 该方法仅适用于直线段组成的路径,如果路径包含贝塞尔曲线,需要额外扩展处理逻辑。
  • 圆角半径不宜超过线段最短长度的一半,否则会导致路径变形或圆弧重叠。
  • 若路径是简单矩形,直接使用Path.addRRect(RRect.fromRectAndRadius(rect, Radius.circular(radius)))会更高效。

内容的提问来源于stack exchange,提问作者Hossein Asadi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:10:31