when I used aync await method at that time it works properly but when i try to load image in flame's component class I got error:
I have created a Background class that extends flame engine's component class. Now I am tring to load a base64 image using the then
function, but I get an error but when I use the async await
method for image loading it works properly.
class Background extends Component with Resizable {
static final Paint _paint = Paint();
Size imageSize = Size(411.42857142857144, 822.8571428571429);
@override
void render(Canvas c) {
Rect myRect = const Offset(0.0, 0.0) & Size(size.width, size.height);
Flame.images.fromBase64('demo', imageBase).then((value) {
paintImage(canvas: c, rect: myRect, image: value);
});
}
@override
void update(double t) {
// TODO: implement update
}
void paintImage({
@required Canvas canvas,
@required Rect rect,
@required image.Image image,
String debugImageLabel,
double scale = 1.0,
ColorFilter colorFilter,
BoxFit fit,
Alignment alignment = Alignment.center,
Rect centerSlice,
ImageRepeat repeat = ImageRepeat.noRepeat,
bool flipHorizontally = false,
bool invertColors = false,
FilterQuality filterQuality = FilterQuality.low,
bool isAntiAlias = false,
}) {
if (rect.isEmpty) return;
Size outputSize = rect.size;
Size inputSize = Size(image.width.toDouble(), image.height.toDouble());
Offset sliceBorder;
if (centerSlice != null) {
sliceBorder = Offset(
centerSlice.left + inputSize.width - centerSlice.right,
centerSlice.top + inputSize.height - centerSlice.bottom,
);
outputSize = outputSize - sliceBorder as Size;
inputSize = inputSize - sliceBorder as Size;
}
fit ??= centerSlice == null ? BoxFit.scaleDown : BoxFit.fill;
assert(centerSlice == null || (fit != BoxFit.none && fit != BoxFit.cover));
final FittedSizes fittedSizes =
applyBoxFit(fit, inputSize / scale, outputSize);
final Size sourceSize = fittedSizes.source * scale;
Size destinationSize = fittedSizes.destination;
if (centerSlice != null) {
outputSize += sliceBorder;
destinationSize += sliceBorder;
}
// Output size is fully calculated.
if (repeat != ImageRepeat.noRepeat && destinationSize == outputSize) {
repeat = ImageRepeat.noRepeat;
}
final Paint paint = Paint()..isAntiAlias = isAntiAlias;
if (colorFilter != null) paint.colorFilter = colorFilter;
if (sourceSize != destinationSize) {
paint.filterQuality = filterQuality;
}
paint.invertColors = invertColors;
final double halfWidthDelta =
(outputSize.width - destinationSize.width) / 2.0;
final double halfHeightDelta =
(outputSize.height - destinationSize.height) / 2.0;
final double dx = halfWidthDelta +
(flipHorizontally ? -alignment.x : alignment.x) * halfWidthDelta;
final double dy = halfHeightDelta + alignment.y * halfHeightDelta;
final Offset destinationPosition = rect.topLeft.translate(dx, dy);
final Rect destinationRect = destinationPosition & destinationSize;
final bool needSave = repeat != ImageRepeat.noRepeat || flipHorizontally;
if (needSave) canvas.save();
if (repeat != ImageRepeat.noRepeat) canvas.clipRect(rect);
if (flipHorizontally) {
final double dx = -(rect.left + rect.width / 2.0);
canvas.translate(-dx, 0.0);
canvas.scale(-1.0, 1.0);
canvas.translate(dx, 0.0);
}
if (centerSlice == null) {
final Rect sourceRect = alignment.inscribe(
sourceSize,
Offset.zero & inputSize,
);
if (repeat == ImageRepeat.noRepeat) {
canvas.drawImageRect(image, sourceRect, destinationRect, paint);
} else {
print("no repet else");
}
}
//if (needSave) canvas.restore();
}
}
This is totally not acceptable:
The render method must be sync. It takes a canvas object to be rendered right now. You cannot make async operations on here! Of course the canvas will be disposed, it only lives for one frame. The render method is called every frame and must be quick and short lived. When the image actually loads, you no longer will have access to canvas because the whole render cycle will be done. It was already rendered on the screen! You cannot change the past! That doesn't make sense.
What you need to do is to load the image elsewhere and render conditionally if it's loaded. Move the loading to your constructor:
And then on the render method, render conditionally:
By creating an image field on your component. Also consider using
SpriteComponent
instead that does all that for you in the correct way. And never make the render or update methods async ;)