nick.tdr
nick.tdr

Reputation: 4933

How to put a Stack as a child of CustomScrollView

I am using a CustomScrollView. I have added a few slivers in it but one of my children has to be a stack which has a list as on of its two children. I tried using SliverToBoxAdapter but that makes the list in the stack non scrollable which is the obvious behaviour. Is there a way to to write some kind of SliverToSliverAdapter? I tried reading the SliverPadding but its looks too complicated for me to understand. Below is my code:

  CustomScrollView(
        key: PageStorageKey<String>(name),
        slivers: <Widget>[
          SliverOverlapInjector(
              handle:
                  NestedScrollView.sliverOverlapAbsorberHandleFor(context)),
          SliverToBoxAdapter(
              child: Stack(
            children: <Widget>[
              Container(
                width: double.infinity,
                height: 50,
                decoration: BoxDecoration(color: pink),
              ),
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 30),
                child: ListView.builder(
                  padding: const EdgeInsets.all(0),
                  shrinkWrap: true,
                  itemBuilder: (context, index) {
                    return buildSongRow(songs[index]);
                  },
                  itemCount: songs.length,
                ),
              )
            ],
          )),
        ],
      );

Upvotes: 2

Views: 2687

Answers (1)

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63569

Stack widget use parent's size by default. While parent widget is CustomScrollView that decide it's size mean, it will get infinite height. To solve this issue, we can wrap Stack with SizedBox(height:x).

Next issue comes on Stack about scrolling and widget visibility. Widget render prioritize bottom to top and same for the scroll event. While Container(height:50) is the first child of Stack, it will be paint behind ListView and in this case we can have full-scroll event on ListView.

We can move Container<height:50> at the bottom to paint it over ListView. In this case, scroll-event won't work on Container<h:50> portion.

We can wrap Container<h:50> and ListView with SizedBox by providing height and use Align or Positioned widget to place them on Stack. Also, we can increase itemCount+1 and use an empty SizedBox(height:50)(on index 0) that will take same amount of height as Container(height:50) and help to view only for 1st time on Stack.

I am using LayoutBuilder to get the size/constraints of screen.

return Scaffold(
      body: LayoutBuilder(
        builder: (context, constraints) => CustomScrollView(
          slivers: [
            const SliverAppBar(
              title: Text("Stack On CustomScrollView"),
            ),
            SliverToBoxAdapter(
              child: SizedBox(
                height: constraints.maxHeight * .3, // used by stack
                child: Stack(
                  children: [
                    Align(
                      alignment: Alignment.topCenter,
                      child: Container(
                        // dont need to use sizedBox here, height is fixed by container's height:50
                        height: 50,
                        color: Colors.pink,
                        alignment: Alignment.center,
                        child: const Text("Stack Child: Container<height: 50>"),
                      ),
                    ),
                    Align(
                      alignment: Alignment.bottomCenter,
                      child: SizedBox(
                        height: constraints.maxHeight * .3 - 50,
                        child: ListView.builder(
                          itemCount: 4,
                          itemBuilder: (context, index) => Container(
                            alignment: Alignment.center,
                            height: 50,
                            color: index.isEven
                                ? Colors.deepOrange
                                : Colors.deepPurple,
                            child: Text("ListViewItem:$index"),
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
            ),
            SliverList(
              delegate: SliverChildListDelegate(
                [
                  ...List.generate(
                    44,
                    (index) => Container(
                      height: 100,
                      alignment: Alignment.center,
                      color: index.isEven ? Colors.cyanAccent : Colors.blueGrey,
                      child: Text("SliverList $index"),
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );

Upvotes: 1

Related Questions