请先看作用
具体步骤: 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,
),
);
},
)
再次看作用
再次历经一周时间
最终版别呈现了!
这样就可以实现一个填色小应用啦~代码粗糙有待优化 提供的是思路 自行修改 好了 能力有限就写这么多啦 多多点赞 点赞 要全套代码请加V:sunyan414361110