I use onBeforePaint: (controller, canvas) lifecycle and use canvas.drawImageRect, not working
How to render a background png with spine_flutter
To render a background PNG with spine_flutter
, you can use the onBeforePaint
callback to draw the image before the skeleton is rendered. Here is a step-by-step guide to achieve this:
Load the Image: Ensure you have loaded the image you want to use as the background. You can use Flutter's
Image
class to load the image.Draw the Image in
onBeforePaint
: Use thecanvas.drawImageRect
method within theonBeforePaint
callback to draw the image. Make sure the coordinates and size are set correctly.
Here is an example code snippet:
import 'package:flutter/material.dart';
import 'package:spine_flutter/spine_flutter.dart';
class SpineBackgroundExample extends StatefulWidget {
@override
_SpineBackgroundExampleState createState() => _SpineBackgroundExampleState();
}
class _SpineBackgroundExampleState extends State<SpineBackgroundExample> {
late SpineWidgetController _controller;
late Image _backgroundImage;
@override
void initState() {
super.initState();
_controller = SpineWidgetController();
_backgroundImage = Image.asset('assets/mybackground.png');
}
@override
Widget build(BuildContext context) {
return SpineWidget(
controller: _controller,
skeletonPath: 'assets/skeleton.json',
atlasPath: 'assets/skeleton.atlas',
onBeforePaint: (controller, canvas) {
// Draw the background image
final paint = Paint();
final src = Rect.fromLTWH(0, 0, _backgroundImage.width.toDouble(), _backgroundImage.height.toDouble());
final dst = Rect.fromLTWH(0, 0, canvas.size.width, canvas.size.height);
canvas.drawImageRect(_backgroundImage, src, dst, paint);
},
);
}
}
In this example:
- The
Image.asset
method is used to load the background image. - The
onBeforePaint
callback is used to draw the image on the canvas before the skeleton is rendered.
Ensure that the image path and the coordinates in drawImageRect
are correct. If the image is not displaying, double-check the image loading and the coordinates used for drawing.
I was tried to excute canvas.restore()
before drawImageRect
, png background would be rendered. But spine file cannot render correctly!!
When rendering onBeforePaint()
, the canvas transformation matrix is set up such, that the skeleton will be rendered according to the alignment and fit parameters set on the SpineWidget
. This also means that when you draw in onBeforePaint()
, you drawing code will operate in the coordinate system of the skeleton being rendered.
If you want to work in the coordinate system of the canvas, you have to temporarily "undo" the transformation SpineWidget
sets on the canvas. E.g.
onBeforePaint: (controller, canvas) {
// Save the current transform and other canvas state
canvas.save();
// Get the current canvas transform an invert it, so we can work in the
// canvas coordinate system.
final currentMatrix = canvas.getTransform();
final invertedMatrix = Matrix4.tryInvert(Matrix4.fromFloat64List(currentMatrix));
if (invertedMatrix != null) {
canvas.transform(invertedMatrix.storage);
}
// Draw something.
final Paint paint = Paint()
..color = Colors.black
..strokeWidth = 2.0;
canvas.drawLine(
Offset(0, 0),
Offset(canvas.getLocalClipBounds().width, canvas.getLocalClipBounds().height),
paint,
);
// Restore the old transform and canvas state
canvas.restore();
}
Alternatively, you can make the SpineWidget have a transparent background, then stack it on top of a Flutter Image
widget that displays your background.
How do you mean? Render multiple skeletons in a single SpineWidget? Or rendering multiple SpineWidget instances each with their own skeleton? The later should work. If it doesn't, please file an issue on GitHub and if you have rewritten the class, sharing your changes could accelerate fixing the bug.
That's not what SpineWidget is made for. If you want more game like functionality, look into Flame and our Flame Integration