Flutter矢量图SVG的区域填色怎么实现
具体步骤: 1.SVG实际上就是一个xml文件,通过flutter自带的package xml进行进行图层解析 import 'package:xml/xml.dart';
这里是解析的部分代码
Futureload() 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 pathNodes = svgRoot.findAllElements('path'); List 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 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 Statewith 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 (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, ), ); }, )