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

如何使用Flutter的CustomPaint实现匹配参考样式的底部内凹弧形资料横幅?

如何使用Flutter的CustomPaint实现匹配参考样式的底部内凹弧形资料横幅?

我完全懂你现在的困扰——想做出那种底部带平滑内凹圆角的资料横幅,但当前CustomPaint画出来的曲线要么形状不对,要么边角过渡生硬,和参考图差了不少对吧?别担心,咱们可以通过调整Path的绘制逻辑,精准复刻你想要的效果。

首先,先给你一套可以直接复用的Path构建逻辑,我会一步步解释每部分的作用,你也能根据自己的UI需求灵活调整参数:

核心Path实现代码

Path buildBannerPath(double width, double height) {
  // 这两个参数是关键,你可以根据参考图调整数值
  final double curveDepth = 20.0; // 底部内凹的深浅程度
  final double cornerRadius = 16.0; // 底部左右圆角的半径

  return Path()
    // 1. 从横幅的左上角开始绘制路径
    ..moveTo(0, 0)
    // 2. 画顶部的水平直线到右上角
    ..lineTo(width, 0)
    // 3. 从右上角画竖直线到右下角圆角的起始点
    ..lineTo(width, height - cornerRadius)
    // 4. 绘制右下角的外圆角,保证过渡自然
    ..arcToPoint(
      Offset(width - cornerRadius, height),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    )
    // 5. 重点:用三次贝塞尔曲线画底部的平滑内凹
    ..cubicTo(
      width * 0.75, height + curveDepth, // 右侧控制点
      width * 0.25, height + curveDepth, // 左侧控制点
      cornerRadius, height, // 曲线的终点(左下角圆角的起始点)
    )
    // 6. 绘制左下角的外圆角,保持左右对称
    ..arcToPoint(
      Offset(0, height - cornerRadius),
      radius: Radius.circular(cornerRadius),
      clockwise: false,
    )
    // 7. 从左下角圆角起点画竖直线回到左上角,闭合路径
    ..lineTo(0, 0)
    ..close();
}

代码逻辑拆解

  • 参数自定义:curveDepth控制内凹的深浅,数值越大内凹效果越明显;cornerRadius控制底部左右圆角的大小,和参考图的圆角尺寸对齐即可。
  • 圆角过渡处理:用arcToPoint绘制底部左右的外圆角,clockwise: false保证圆角的绘制方向正确,避免出现反向的怪异圆角。
  • 平滑内凹曲线:这里选用cubicTo(三次贝塞尔曲线)来实现,两个控制点都设置在height + curveDepth的位置,能让中间的曲线自然内凹,过渡比二次贝塞尔曲线更顺滑。你可以调整控制点的x坐标(比如把0.75改成0.6,0.25改成0.4)来微调曲线的弧度,直到和参考图完全匹配。

在CustomPaint中快速使用

把上面的Path放到自定义Painter里就能直接用了,示例如下:

CustomPaint(
  size: const Size(double.infinity, 120), // 设置你需要的横幅高度
  painter: _BannerPainter(),
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    // 这里放你的资料内容,比如头像、用户名、简介等
    child: Row(
      children: [
        const CircleAvatar(radius: 30),
        const SizedBox(width: 16),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text("用户名", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            Text("用户简介", style: TextStyle(fontSize: 14, color: Colors.grey)),
          ],
        ),
      ],
    ),
  ),
);

// 自定义Painter类
class _BannerPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blueAccent // 替换成你需要的横幅背景色
      ..style = PaintingStyle.fill;

    final path = buildBannerPath(size.width, size.height);
    canvas.drawPath(path, paint);
  }

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

微调适配技巧

  • 如果觉得内凹曲线不够贴合参考图,可以尝试调整cubicTo的控制点位置:比如把右侧控制点设为Offset(width*0.6, height + curveDepth),左侧设为Offset(width*0.4, height + curveDepth),这样曲线的内凹弧度会更集中在中间。
  • 要是想要更简单的曲线实现,也可以用quadraticBezierTo代替cubicTo,代码如下(但平滑度略逊于三次贝塞尔):
..quadraticBezierTo(
  width * 0.5, height + curveDepth,
  cornerRadius, height,
)

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 13:19:33