升级flutter_svg至2.0.7后DrawableRoot失效,如何设置尺寸与颜色?
解决flutter_svg 2.x中SVG字符串转带尺寸/颜色的ui.Image问题
核心实现思路
flutter_svg 2.x废弃DrawableRoot后,需通过PictureRecorder手动管控绘制流程:在绘制SVG的Picture时指定尺寸缩放比例,同时通过Paint设置颜色滤镜,最终生成符合需求的ui.Image。
具体步骤与代码示例
import 'dart:ui' as ui; import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart' as vg; Future<ui.Image> svgStringToImage( String svgString, Size targetSize, Color targetColor, ) async { // 1. 从字符串加载原始SVG矢量图 final svgBytes = utf8.encode(svgString); final picture = await vg.loadPicture( vg.SvgBytesLoader(svgBytes), null, ); // 2. 计算缩放比例(保持SVG原始宽高比,避免拉伸) final svgSize = Size(picture.width.toDouble(), picture.height.toDouble()); final scaleX = targetSize.width / svgSize.width; final scaleY = targetSize.height / svgSize.height; final scale = min(scaleX, scaleY); // 可选:计算居中偏移,让SVG在目标尺寸内居中显示 final offsetX = (targetSize.width - svgSize.width * scale) / 2; final offsetY = (targetSize.height - svgSize.height * scale) / 2; // 3. 创建绘制记录器与画布 final recorder = ui.PictureRecorder(); final canvas = ui.Canvas(recorder, Rect.fromLTWH(0, 0, targetSize.width, targetSize.height)); // 4. 应用偏移、缩放与颜色滤镜 canvas.save(); canvas.translate(offsetX, offsetY); canvas.scale(scale); final paint = ui.Paint() ..colorFilter = ui.ColorFilter.mode(targetColor, ui.BlendMode.srcIn); // 保留SVG透明度,替换颜色 canvas.drawPicture(picture, paint); canvas.restore(); // 5. 生成并返回最终ui.Image final processedPicture = recorder.endRecording(); final image = await processedPicture.toImage( targetSize.width.toInt(), targetSize.height.toInt(), ); // 释放资源,避免内存泄漏 picture.dispose(); processedPicture.dispose(); return image; }
适配ShaderMask的用法示例
生成的ui.Image可直接用于创建水印Shader:
// 生成水印Image final watermarkImage = await svgStringToImage( '<svg>你的SVG字符串内容</svg>', Size(120, 120), Colors.grey.withOpacity(0.3), ); // 创建重复平铺的Shader final watermarkShader = ImageShader( watermarkImage, TileMode.repeated, TileMode.repeated, Matrix4.identity().storage, ); // 用于ShaderMask实现水印效果 ShaderMask( shaderCallback: (bounds) => watermarkShader, blendMode: BlendMode.srcOver, child: Container( width: double.infinity, height: double.infinity, child: yourTargetContentWidget, // 需要添加水印的内容组件 ), )
内容的提问来源于stack exchange,提问作者Hasan Shaddad
相关产品推荐
相关产品推荐

