Search code examples
flutterconditional-statementsstackrenderingbuilding

How to sync the Stack building order *Not the Z-order


Description:

I have a Stack with two Widgets. Widget1 (as a background) being a Grid of 4 AssetImages and Widget2 being a semi-transparent rectangular coloured Container building on top of Widget1. The Stack is building both widgets as expected!

Problem:

Widget2 is visually rendered before Widget1, which leads to an awkward effect because Widget2 is rendered over an empty background. I assume that this is caused by Stack async building of children however AssetImage is a synchronous call...

Question:

How to make Widget2 rendering to wait for widget1 until Widget1 gets fully visual as the background?

Notice that I have already tried WidgetBindings.instance.addPostframeCallback

Many Thanks,


Solution

  • Solution 1

    I think there is no need to wait for widget1. You can pre-cache the widget1 and widget2 assets with precacheImage way before displaying them. This way they're going to show almost immediately.

    await precacheImage(AssetImage('assets/widget1.png'), context);
    await precacheImage(AssetImage('assets/widget2.png'), context);
    

    From the docs, after the call of precacheImage:

    If the image is later used by an Image or BoxDecoration or FadeInImage, it will probably be loaded faster. The consumer of the image does not need to use the same ImageProvider instance. The ImageCache will find the image as long as both images share the same key, and the image is held by the cache.

    Solution 2

    Otherwise, you can use Future.delayed to wait a bit for the widget1 to get rendered. The call to delayed should setState of some flag that builds the widget2, let's say bool _buildWidget2 = false flag. Something like the below code snippet:

    Future.delayed(
      Duration(milliseconds: 150),
      () => setState(() => _buildWidget2 = true),
    );
    

    And then on the Stack it should be something:

    Stack(
      children: [
        Widget1(),
        if (_buildWidget2)
          Widget2(),
      ],
    )