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

Flutter实现移动线条沿圆角矩形边缘贴合曲线移动方案问询

解决方案:让红色线条跟随圆角曲线

问题出在当前代码是基于路径的切线方向绘制直线,而非沿着圆角矩形的路径曲线本身绘制线段,因此在圆角区域无法贴合曲线走向。要实现线条沿曲线跟随,需要直接从路径上截取对应长度的线段,而非绘制切线直线。

修改核心逻辑

替换原代码中绘制红色线条的部分,使用PathMetric.extractPath方法从路径中截取一段曲线段:

// 移除原drawLine逻辑,替换为路径截取绘制
final movingLinePaint = Paint()
  ..color = Colors.red
  ..strokeWidth = 10.0
  ..strokeCap = StrokeCap.round
  ..style = PaintingStyle.stroke;

// 处理边界,避免超出路径长度
double currentLength = pathMetric.length * animation.value;
currentLength = currentLength.clamp(0.0, pathMetric.length);
double endLength = currentLength + 30;
endLength = endLength.clamp(currentLength, pathMetric.length);

// 从当前位置截取一段路径
Path segmentPath = pathMetric.extractPath(currentLength, endLength);
canvas.drawPath(segmentPath, movingLinePaint);

完整修改后的Painter代码

class RoundedRectanglePainter extends CustomPainter {
  final Color strokeColorGradientStart;
  final Color strokeColorGradientEnd;
  final double strokeWidth;
  final double borderRadius;
  final Color fillColorGradientStart;
  final Color fillColorGradientEnd;
  final Animation<double> animation;

  RoundedRectanglePainter({
    required this.strokeColorGradientStart,
    required this.strokeColorGradientEnd,
    required this.strokeWidth,
    required this.borderRadius,
    required this.fillColorGradientStart,
    required this.fillColorGradientEnd,
    required this.animation,
  }) : super(repaint: animation);

  @override
  void paint(Canvas canvas, Size size) {
    final strokeGradient = LinearGradient(
      colors: [strokeColorGradientStart, strokeColorGradientEnd],
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
    );

    final fillGradient = LinearGradient(
      colors: [fillColorGradientStart, fillColorGradientEnd],
      begin: Alignment.topLeft,
      end: Alignment.bottomRight,
    );

    final strokePaint = Paint()
      ..shader = strokeGradient
          .createShader(Rect.fromLTWH(0, 0, size.width, size.height))
      ..strokeWidth = strokeWidth
      ..style = PaintingStyle.stroke;

    final fillPaint = Paint()
      ..shader = fillGradient
          .createShader(Rect.fromLTWH(0, 0, size.width, size.height))
      ..style = PaintingStyle.fill;

    final outerRect = Rect.fromLTWH(0, 0, size.width, size.height);
    final outerRRect =
        RRect.fromRectAndRadius(outerRect, Radius.circular(borderRadius));
    canvas.drawRRect(outerRRect, strokePaint);

    final innerWidth = size.width - (strokeWidth * 2) - 10;
    final innerHeight = size.height - (strokeWidth * 2) - 10;
    final innerRect = Rect.fromLTWH((size.width - innerWidth) / 2,
        (size.height - innerHeight) / 2, innerWidth, innerHeight);
    final innerRRect =
        RRect.fromRectAndRadius(innerRect, Radius.circular(borderRadius));

    canvas.drawRRect(innerRRect, fillPaint);

    Path outerPath = Path()..addRRect(outerRRect);
    PathMetrics pathMetrics = outerPath.computeMetrics();
    PathMetric pathMetric = pathMetrics.first;

    // 绘制跟随路径的红色线段
    final movingLinePaint = Paint()
      ..color = Colors.red
      ..strokeWidth = 10.0
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke;

    double currentLength = pathMetric.length * animation.value;
    currentLength = currentLength.clamp(0.0, pathMetric.length);
    double endLength = currentLength + 30;
    endLength = endLength.clamp(currentLength, pathMetric.length);
    
    Path segmentPath = pathMetric.extractPath(currentLength, endLength);
    canvas.drawPath(segmentPath, movingLinePaint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

关键说明

  1. 路径截取:extractPath方法直接从原始路径中提取指定区间的线段,无论是直线还是圆角曲线,都能完整保留路径形状,自然贴合圆角走向。
  2. 边界处理:用clamp方法限制长度范围,避免动画值超出路径长度时出现异常。
  3. 视觉优化:保留StrokeCap.round让线段两端更圆润,提升视觉效果。

内容的提问来源于stack exchange,提问作者Saurav Navneet

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 09:22:03