Flutter: How to put a CupertinoActivityIndicator into a customScrollView with SliverList

Issue

This is a mockup of what I want to achieve – it is a CupertinoActivityIndicator underneath a CupertinoSliverNavigationBar for notifying the user that the data is being downloaded.
enter image description here

Once it is downloaded, it should look like so:

enter image description here

Now, I have been trying to get this effect using the following code:

 List<Trade> trades = [];

  showLoadingDialog() {
    return trades.length == 0;
  }

  getBody() {
    if (showLoadingDialog()) {
      return getProgressDialog();
    } else {
      return getTradeItemList();
    }
  }

  getTradeItemList() {
    return new CupertinoPageScaffold(
        child: new CustomScrollView(slivers: <Widget>[
      const CupertinoSliverNavigationBar(
        largeTitle: const Text('Coffee Shop'),
      ),
      getBody(),
    ]));
  }

  getProgressDialog() {
    return new Container(
        decoration: const BoxDecoration(
          color: CupertinoColors.white,
        ),
        child: new Center(child: const CupertinoActivityIndicator()));
  }

However, I’m receiving this error because I’m trying to put a non-RenderSliver type into a Sliver. In other words, I’m putting in an CupertinoActivityIndicator into a Sliver and the code is rejecting it.

══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY
╞═══════════════════════════════════════════════════════════ The
following assertion was thrown building Container(bg:
BoxDecoration(color: Color(0xffffffff))): A RenderViewport expected a
child of type RenderSliver but received a child of type
RenderDecoratedBox. RenderObjects expect specific types of children
because they coordinate with their children during layout and paint.
For example, a RenderSliver cannot be the child of a RenderBox because
a RenderSliver does not understand the RenderBox layout protocol.

The closest I could get to achieving the effect I want is displayed in the gif below. However, as you can clearly see, the CupertinoSliverNavigationBar is not being displayed when the CupertinoActivityIndicator is visible. It is only after the data has been downloaded that the CupertinoSliverNavigationBar that says “Coffee Shop” is visible.

enter image description here

I achieved the above using the following code:

  List<Trade> trades = [];

  showLoadingDialog() {
    return trades.length == 0;
  }

  getBody() {
    if (showLoadingDialog()) {
      return getProgressDialog();
    } else {
      return getTradeItemList();
    }
  }

  getProgressDialog() {
    return new Container(
        decoration: const BoxDecoration(
          color: CupertinoColors.white,
        ),
        child: new Center(child: const CupertinoActivityIndicator()));
  }


  getTradeItemList() {
    return new CupertinoPageScaffold(
      child: new CustomScrollView(
        slivers: <Widget>[
          const CupertinoSliverNavigationBar(
            largeTitle: const Text('Coffee Shop'),
          ),
          new SliverPadding(
            // Top media padding consumed by CupertinoSliverNavigationBar.
            // Left/Right media padding consumed by Tab1RowItem.
            padding: MediaQuery
                .of(context)
                .removePadding(
                  removeTop: true,
                  removeLeft: true,
                  removeRight: true,
                )
                .padding,
            sliver: new SliverList(
              delegate: new SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  return new Tab1RowItem(
                    index: index,
                    lastItem: index == trades.length - 1,
                    color: "Coffee Beans",
                    colorName: "Buy coffee now",
                  );
                },
                childCount: trades.length,
              ),
            ),
          )
        ],
      ),
    );
  }


  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return getBody();
  }

  @override
  void initState() {
    super.initState();
    loadDataTrades();
  }

Can anyone tell me how I can achieve the effect I want?

Solution

 Widget _mainFrame;


@override
  Widget build(BuildContext context) {
    return new CustomScrollView(
      slivers: <Widget>[

        new CupertinoSliverNavigationBar(
          largeTitle: const Text("Coffe Shop"),
        ),

        _mainFrame,

      ],
    );
  }


Widget _beforeDataLoaded() {
    return new SliverFillRemaining(
      child:  new Container(
        child: new Center(
          child: new CupertinoActivityIndicator(),
        ),
      ),
    );
  }



Widget _dataLoadComplete() {
    return new SliverList(
      // Your list items
    );
  }

You change the _mainFrame Widget from the CupertionActivityIndicator to your listview if the load finished.

Answered By – Lukas Kirner

Answer Checked By – Mildred Charles (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *