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

Flutter如何在单个CustomPaint画布上绘制两个重叠圆形图标

问题描述

我希望在CustomPaint画布上实现两个重叠的圆形图标,效果与文末参考示意图一致。目前不清楚如何为Paint组件添加子组件,或是将图标放置在CustomPaint()组件上后叠加到画布,需要找到可行方案,在同一个画布内完成两个图标的重叠排布。

现有实现

单圆形图标实现效果
对应页面代码:

return Container(
  height: 170,
  width: 300,
  margin: EdgeInsets.only(bottom: 20, left: 20, right: 20),
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(30),
    color: Color(0xFFf7f7f7),
  ),
  child:Row(
    children: [
      Expanded(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
                  Align(
                    alignment: Alignment(1.5, 5),
                    child: Text(
                      "Zilla Card",
                      textAlign: TextAlign.left,
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                  ),
            SizedBox(height: 20),
            Align(
              alignment: Alignment(1.5, 5),
              child: Text(
                "$4,158.29",
                textAlign: TextAlign.left,
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            Align(
              alignment: Alignment(1.5, 5),
              child: Text(
                "**** 5722",
                textAlign: TextAlign.left,
              ),
            ),
          ],
        ),
      ),
      Stack(
        children: [
              Container(
                width: 230,
                height: 170,
                child: CustomPaint(
                  size: Size(230,(300*0.5666666666666667).toDouble()),
                  painter: RPSCustomPainter(),
                ),
              ),
          Align(
            alignment: Alignment(1, 1),
            child: Container(
              height: 20,
              width: 20,
              alignment: FractionalOffset(2, 0),
              //child: Image.asset("assets/images/overlap.png"),
              clipBehavior: Clip.none,
            ),
          ),

        ],
      ),
    ],
  ),
);

CustomPainter现有代码

目前已经在画布上成功绘制了第一个圆形图标,但尝试绘制第二个图标时出现 The name 'icon' is already defined 错误,原因是第一个图标已经占用了icon变量名。

class RPSCustomPainter extends CustomPainter{
@override
void paint(Canvas canvas, Size size) {
Paint paint0 = Paint()  
..color = Color(0xFF004952)
..style = PaintingStyle.fill  
..strokeWidth = 1;
Path path0 = Path();
path0.moveTo(size.width,size.height*0.2347647);
path0.lineTo(size.width,size.height*0.3320588);
path0.quadraticBezierTo(size.width,size.height*0.7058235,size.width,size.height*0.8304118);
path0.cubicTo(size.width*1.0056000,size.height*0.9074118,size.width*0.9682667,size.height*0.9868824,size.width*0.9194667,size.height);
path0.cubicTo(size.width*0.7554333,size.height*0.9941176,size.width*0.4273667,size.height,size.width*0.2633333,size.height);
path0.cubicTo(size.width*0.3417000,size.height*0.9793529,size.width*0.2974667,size.height*0.7336471,size.width*0.4286667,size.height*0.6625294);
path0.cubicTo(size.width*0.5660333,size.height*0.6025294,size.width*0.6275667,size.height*0.6554118,size.width*0.7332333,size.height*0.3844118);
path0.quadraticBezierTo(size.width*0.8802000,size.height*0.1584706,size.width,size.height*0.1562353);
path0.lineTo(size.width,size.height*0.2347647);
path0.close();

canvas.drawPath(path0, paint0);


Paint paint1 = Paint()
  ..color = Color(0XFFe8f64b)
  ..style = PaintingStyle.fill
  ..strokeWidth = 1;


Path path1 = Path();
path1.moveTo(size.width*0.9584333,size.height*0.1626471);
path1.cubicTo(size.width*0.8021333,size.height*0.1377647,size.width*0.6861667,size.height*0.2499412,size.width*0.6637667,size.height*0.3031765);
path1.cubicTo(size.width*0.5617333,size.height*0.4976471,size.width*0.4517000,size.height*0.5153529,size.width*0.3221333,size.height*0.6101765);
path1.cubicTo(size.width*0.2196000,size.height*0.6835882,size.width*0.1613667,size.height*0.9211765,size.width*0.1905667,size.height);
path1.cubicTo(size.width*0.2107167,size.height,size.width*0.2510167,size.height,size.width*0.2711667,size.height);
path1.cubicTo(size.width*0.3202333,size.height*0.9939412,size.width*0.3097000,size.height*0.7321176,size.width*0.4311667,size.height*0.6568824);
path1.cubicTo(size.width*0.6090333,size.height*0.6081765,size.width*0.6445000,size.height*0.5932941,size.width*0.7236667,size.height*0.4056471);
path1.cubicTo(size.width*0.7604333,size.height*0.3480588,size.width*0.8155333,size.height*0.2334118,size.width*0.9584333,size.height*0.1626471);
path1.close();

canvas.drawPath(path1, paint1);

final icon = Icons.circle_outlined;
TextPainter textPainter = TextPainter(textDirection: TextDirection.rtl);
textPainter.text = TextSpan(text: String.fromCharCode(icon.codePoint),
    style: TextStyle(fontSize: 40.0,fontFamily: icon.fontFamily));
textPainter.layout();
textPainter.paint(canvas, Offset(170.0,100.0));
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}

}

目标实现效果

目标重叠图标效果

解决方案

问题根因

命名冲突错误是因为同一作用域下重复使用了icon、textPainter作为变量名,Dart不允许同名变量存在。不需要在外层Stack额外叠加组件,所有绘制逻辑都可以在同一个CustomPainter内完成。

实现要点

  • 命名区分:两个图标分别使用独立的变量名存储图标数据和TextPainter实例,避免命名冲突
  • 层级控制:CustomPaint按代码书写顺序渲染内容,先执行的绘制逻辑在底层,后执行的在上层,调整两个图标的绘制坐标即可实现错位重叠效果
  • 位置适配:优先使用画布size做相对坐标计算,减少硬编码偏移值,避免不同设备尺寸下出现错位

代码修改示例

将原有绘制单个图标的代码替换为以下内容即可:

// 绘制底层圆形图标
final firstIcon = Icons.circle_outlined;
TextPainter firstIconPainter = TextPainter(textDirection: TextDirection.rtl);
firstIconPainter.text = TextSpan(
  text: String.fromCharCode(firstIcon.codePoint),
  style: TextStyle(
    fontSize: 40.0,
    fontFamily: firstIcon.fontFamily,
    color: Colors.white
  )
);
firstIconPainter.layout();
firstIconPainter.paint(canvas, Offset(160.0, 95.0));

// 绘制上层错位圆形图标
final secondIcon = Icons.circle_outlined;
TextPainter secondIconPainter = TextPainter(textDirection: TextDirection.rtl);
secondIconPainter.text = TextSpan(
  text: String.fromCharCode(secondIcon.codePoint),
  style: TextStyle(
    fontSize: 40.0,
    fontFamily: secondIcon.fontFamily,
    color: Color(0XFFe8f64b)
  )
);
secondIconPainter.layout();
secondIconPainter.paint(canvas, Offset(180.0, 105.0));

可以根据实际显示效果微调两个Offset的横纵坐标值,直到重叠效果和参考图一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 07:48:58