在Flutter Canvas中使用flutter_svg绘制SVG及图形遇到问题
问题分析与解决方案
你的代码核心问题是在paint方法里执行异步加载SVG的操作——paint是同步执行的绘制方法,当异步回调(then里的代码)触发时,当前的绘制周期已经结束,Canvas的绘制上下文早已失效,所以SVG图像根本画不出来。另外热重载时的空引用警告,也是因为异步回调里引用的对象(比如paint、Canvas)可能已经被销毁。
正确的实现思路
- 提前预加载SVG资源:在组件初始化阶段(比如
initState)完成SVG的加载,不要放到paint里。 - 管理加载状态:用状态变量保存加载好的
Picture或Image,加载完成后触发重绘。 - 同步绘制:在
paint里直接使用预加载好的资源进行同步绘制。
完整代码示例
import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class SvgCanvasDemo extends StatefulWidget { const SvgCanvasDemo({super.key}); @override State<SvgCanvasDemo> createState() => _SvgCanvasDemoState(); } class _SvgCanvasDemoState extends State<SvgCanvasDemo> { Picture? _svgPicture; @override void initState() { super.initState(); // 初始化时预加载SVG _loadSvg(); } Future<void> _loadSvg() async { final svgPicture = await vg.loadPicture( const SvgAssetLoader("assets/Monogramme_dark.svg"), null, ); setState(() { _svgPicture = svgPicture.picture; }); } @override Widget build(BuildContext context) { return CustomPaint( painter: _MyCanvasPainter(svgPicture: _svgPicture), size: const Size(double.infinity, double.infinity), ); } } class _MyCanvasPainter extends CustomPainter { final Picture? svgPicture; _MyCanvasPainter({this.svgPicture}); @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = const Color.fromARGB(255, 15, 9, 184); // 绘制蓝色圆形 canvas.drawCircle(const Offset(50.0, 20.0), 10, paint); // SVG加载完成后绘制 if (svgPicture != null) { // 方法1:直接绘制Picture(推荐,比转Image更高效) canvas.save(); canvas.translate(100, 100); // 定位SVG canvas.scale(0.5); // 根据需要缩放 canvas.drawPicture(svgPicture!); canvas.restore(); // 方法2:转成Image绘制(如果需要对Image做更多处理) // svgPicture!.toImage(50, 50).then((image) { // // 注意:如果要在这里绘制,需要确保当前Canvas有效,建议用方法1 // canvas.drawImage(image, const Offset(100, 100), paint); // }); } } @override bool shouldRepaint(_MyCanvasPainter oldDelegate) { // 当SVGPicture变化时触发重绘 return oldDelegate.svgPicture != svgPicture; } }
关键说明
- 预加载资源:把SVG加载逻辑放到
initState里,确保在绘制前完成加载,加载完成后通过setState触发重绘。 - 直接绘制Picture:
flutter_svg返回的Picture可以直接用canvas.drawPicture绘制,比转成Image更高效,还能保留矢量特性(缩放不失真)。 - shouldRepaint逻辑:当传入的
svgPicture变化时(从null变成加载好的Picture),告诉Flutter需要重绘,这样SVG就能显示出来。
内容的提问来源于stack exchange,提问作者pim999
相关产品推荐
相关产品推荐

