0

当我当时使用 aync await 方法时它可以正常工作但是当我尝试在火焰的组件类中加载图像时出现错误:

我创建了一个扩展火焰引擎组件类的背景类。现在我正在尝试使用该then函数加载 base64 图像,但出现错误,但是当我使用异步await方法加载图像时,它可以正常工作。

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();
    }
}
4

1 回答 1

2

这是完全不能接受的:

    @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);
        });
    }

渲染方法必须是sync。现在需要一个画布对象来渲染。你不能在这里进行异步操作!当然画布会被处理掉,它只存在一帧。渲染方法在每一帧都被调用,并且必须是快速而短暂的。当图像实际加载时,您将无法再访问画布,因为整个渲染周期都将完成。它已经呈现在屏幕上!你无法改变过去!那没有意义。

您需要做的是将图像加载到其他地方并在加载时有条件地渲染。将加载移动到您的构造函数:

        Flame.images.fromBase64('demo', imageBase).then((value) {
            this.image = value;
        });

然后在 render 方法上,有条件地渲染:

    @override
    void render(Canvas c) {
        Rect myRect = const Offset(0.0, 0.0) & Size(size.width, size.height);
        if (this.image != null) {
            paintImage(canvas: c, rect: myRect, image: this.image);
        }
    }

通过在您的组件上创建一个图像字段。还可以考虑使用SpriteComponent它以正确的方式为您完成所有工作。并且永远不要使渲染或更新方法异步;)

于 2020-10-02T15:06:07.947 回答