目录 请先看效果 再次看效果 请先看效果 具体步骤: 1.SVG实际上就是一个xml文件,通过flutter自带的package xml进行进行图层解析 import package:xml/xml.dart; 这里是解析的部分代码 Futurevoid load()
目录
- 请先看效果
- 再次看效果
请先看效果
具体步骤: 1.SVG实际上就是一个xml文件,通过flutter自带的package xml进行进行图层解析 import 'package:xml/xml.dart';
这里是解析的部分代码
Future<void> load() async { draws.clear(); colors.clear(); actualColors.clear(); String assetName = 'lib/1057.svg'; String svg = await rootBundle.loadString(assetName); final document = XmlDocument.parse(svg); final svgRoot = document.rootElement; Iterable<XmlElement> pathNodes = svgRoot.findAllElements('path'); List<XmlElement> pathNodesList = pathNodes.toList(); RegExp colorRegex = RegExp(r"#\w{6}"); for (int i = 0; i < pathNodesList.length; i++) { XmlElement element = pathNodesList[i]; String? d = element.getAttribute('d'); final Path path = parseSvgPathData(d ?? ''); draws.add(path); String? style = element.getAttribute('style'); assemblyColor(colorRegex, style); } setState(() {}); }
2.绘制到canvas上:解析完成后,就是绘制呀 这里是绘制的代码
class MyPainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { for (int i = 0; i < draws.length; i++) { Path path = draws[i]; canvas.drawPath(path, Paint()..color = colors[i]); } } Future<void> onTap(Offset offset) async { for (int i = 0; i < draws.length; i++) { Path path = draws[i]; if (path.contains(offset)) { colors[i] = actualColors[i]; return; } } } @override bool shouldRepaint(CustomPainter oldDelegate) => true; }
3.容器缩放:绘制完成后,一定要缩放啊 不然小小的多不开心 这里是容器的代码
@override Widget build(BuildContext context) { var width = MediaQuery.of(context).size.width; return InteractiveViewer( boundaryMargin: const EdgeInsets.all(50), maxScale: 6, child: OverflowBox( child: GestureDetector( onTapDown: (TapDownDetails details) { Offset offset = Offset( details.localPosition.dx / (width / size.width), details.localPosition.dy / (width / size.width)); _painter.onTap(offset); setState(() {}); // 在这里处理点击事件 }, child: Container( color: Colors.white, width: width, height: width, child: Center( child: Transform.translate( offset: Offset( -(size.width - width) / 2.0 * (width / size.width), -(size.width - width) / 2.0 * (width / size.width)), child: Transform.scale( scale: width / size.width, child: RepaintBoundary( child: CustomPaint( isComplex: true, size: Size(size.width, size.width), painter: MyPainter(), ), ), ), ), ), ), ), ), ); } }
4.动画:如此看来现在点击填充的时候是不是有个动画就更好了?
class _FillWidgetState extends State<FillWidget> with SingleTickerProviderStateMixin { @override void initState() { _animationController = AnimationController( duration: const Duration(milliseconds: 500), vsync: this) ..repeat(reverse: true) ..addStatusListener((status) { if (status == AnimationStatus.completed) { print("Animation completed"); setState(() {}); } else if (status == AnimationStatus.dismissed) { print("Animation dismissed"); } }); _radiusAnimation = Tween<double>(begin: 0.0, end: 1.0).animate(_animationController); load(); super.initState(); } child: AnimatedBuilder( animation: _animationController, builder: (BuildContext context, Widget? child) { return RepaintBoundary( child: CustomPaint( key: UniqueKey(), isComplex: true, size: Size(size.width, size.width), painter: _painter, ), ); }, )
再次看效果
这样就可以实现一个填色小应用啦~代码粗糙有待优化 提供的是思路 自行修改 好了 能力有限就写这么多啦~更多关于Flutter矢量图SVG区域填色的资料请关注自由互联其它相关文章!