如何使用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
相关产品推荐
相关产品推荐

