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

Flutter中如何实现线条的斜角截断?

问题描述

通过继承CustomPainter类绘制线条时,无法实现截图所示的斜角截断效果,现有代码如下,附当前效果与期望效果截图:

绘制代码

class StationPointPainter extends CustomPainter {
  StationPointPainter({});

  @override
  void paint(Canvas canvas, Size size) {
    final strokeWidthThin = size.width * 0.07;
    Paint paintMain = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidthThin
      ..color = constants.Colors.purpleMain;

    Paint paintPurpleThin = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidthThin
      ..color = constants.Colors.purpleMain;

    Paint paintPurpleBold = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = size.width * 0.16
      ..shader = ui.Gradient.linear(
          Offset(size.width * 0.54, size.height * 1.03),
          Offset(
            size.width / 2 + size.width * 0.3,
            size.height * 0.45,
          ),
          [
            constants.Colors.red,
            constants.Colors.green
          ],
          [
            0.3,
            0.6,
          ]);

    Paint paintGreen = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidthThin
      ..color = constants.Colors.purpleMainDark.withOpacity(isClosed ? 0.5 : 1);

    Paint paintTransparent = Paint()
      ..style = PaintingStyle.stroke
      ..strokeWidth = size.width * 0.04
      ..color = constants.Colors.purpleMainDark;

    final pathMain = Path()
      ..moveTo(size.width / 2, size.height * 1.05)
      ..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4)
      ..arcToPoint(
        Offset(size.width - size.width * 0.2, size.height * 0.8),
        clockwise: true,
        radius: const Radius.circular(0.9),
      )
      ..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.4);

    final pathGreen = Path()
      ..moveTo(size.width / 2 + size.width * 0.3, size.height * 0.4)
      ..lineTo(size.width / 2, size.height)
      ..arcToPoint(
        Offset(size.width - size.width * 0.22, size.height * 0.26),
        clockwise: true,
        radius: const Radius.circular(0.9),
      );

    final pathPurpleThin = Path()
      ..moveTo(size.width / 2, size.height * 1.05)
      ..lineTo(size.width / 2 - size.width * 0.3, size.height * 0.4);

    final pathPurpleBold = Path()
      ..moveTo(size.width * 0.54, size.height * 1.03)
      ..lineTo(size.width / 2 + size.width * 0.3, size.height * 0.45);

    final pathTransparent = Path()
      ..moveTo(size.width * 0.44, size.height)
      ..lineTo(size.width * 0.58, size.height * 0.68);

    pathMain.close();
    pathGreen.close();
    pathPurpleThin.close();
    pathTransparent.close();

    if (!isClosed) {
      canvas.drawPath(pathMain, paintMain);
      canvas.drawPath(pathGreen, paintGreen);
      canvas.drawPath(pathPurpleThin, paintPurpleThin);
      canvas.drawPath(pathTransparent, paintTransparent);
    }

    canvas.drawPath(pathPurpleBold, paintPurpleBold);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

布局代码

ClipPath(
            clipper: StationPointClipper(),
            child: Container(
              width: width,
              height: height,
              color: constants.Colors.purpleMainDark,
              child: CustomPaint(
                painter: StationPointPainter(),
              ),
            ),
          ),

当前效果

当前效果

期望效果

期望效果

解决方法

要实现斜角截断效果,不能用描边模式绘制粗线条,需改为填充闭合的梯形路径模拟斜角线条,具体修改如下:

  1. 修改画笔模式为填充
    将paintPurpleBold的style从PaintingStyle.stroke改为PaintingStyle.fill,移除strokeWidth(填充模式无需该参数):

    Paint paintPurpleBold = Paint()
      ..style = PaintingStyle.fill
      ..shader = ui.Gradient.linear(
          Offset(size.width * 0.54, size.height * 1.03),
          Offset(
            size.width / 2 + size.width * 0.3,
            size.height * 0.45,
          ),
          [
            constants.Colors.red,
            constants.Colors.green
          ],
          [
            0.3,
            0.6,
          ]);
    
  2. 构建梯形路径
    基于原线条的起点、终点和宽度,计算梯形的四个顶点,绘制闭合路径:

    final boldStrokeWidth = size.width * 0.16;
    final startPoint = Offset(size.width * 0.54, size.height * 1.03);
    final endPoint = Offset(size.width / 2 + size.width * 0.3, size.height * 0.45);
    // 计算线条垂直方向的偏移向量
    final dir = endPoint - startPoint;
    final perpDir = Offset(-dir.dy, dir.dx).normalized * (boldStrokeWidth / 2);
    // 斜角延伸长度,可按需调整以改变斜角尖锐度
    final angleExtend = dir.normalized * (boldStrokeWidth / 2);
    
    final pathPurpleBold = Path()
      ..moveTo(startPoint - perpDir)
      ..lineTo(startPoint + perpDir)
      ..lineTo(endPoint + perpDir + angleExtend)
      ..lineTo(endPoint - perpDir + angleExtend)
      ..close();
    
  3. 替换原绘制逻辑
    用新的pathPurpleBold替换原直线路径,直接填充即可得到斜角截断的粗线条。

调整angleExtend的乘数可以改变斜角的长度与角度,匹配你的期望效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 10:30:49