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
相关产品推荐
相关产品推荐

