Search code examples
flutterdartflutter-layout

How to share the scrollbar between container and gridview in flutter?


I have a column and inside it a page title then Griview.count to display a grid of items.

The gridview scrolls fine downward but the title stays always on top so is not scrollable in the default implementation. I changed the physics: NeverScrollableScrollPhysics(), for the gridview and then the grid itself does not scroll.

Afterward I wrapped the container in SingleChildScrollView and ended up with a partially buggy working solution.

The simplified code so far is:

class ExampleView extends StatefulWidget {
  const ExampleView({Key? key}) : super(key: key);

  @override
  _ExampleViewState createState() => _ExampleViewState();
}

class _ExampleViewState extends State<ExampleView> {
  @override
  Widget build(BuildContext context) {
    return _buildBody(['afsfdfdss', 'dffdfd', 'item3', 'item4 just example']);
  }

  Widget _buildBody(List<String> data) {
    return SingleChildScrollView(
      child: Container(
        height: MediaQuery
            .of(context)
            .size
            .height,
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Text('Some title'),
            const SizedBox(
              height: 16,
            ),
            Flexible(
              child: GridView.count(
                primary: false,
                physics: NeverScrollableScrollPhysics(),
                crossAxisSpacing: 8,
                mainAxisSpacing: 8,
                crossAxisCount: 2,
                children: List<Widget>.generate(data.length,
                        (index) => _buildItem(index, data[index])),
              ),
            )
          ],
        ),
      ),
    );
  }

  Widget _buildItem(int index, String item) {
    return Text(item);
  }
}

Note: I used SingleChildScrollView to wrap the container and because it needs to know the height I used mediaquery.

This works partially. I can scroll down the title is scrolling but cannot go until the end of the Gridview!!! so I see the items cropper and not all of them.

If I increase the height for instance:

height: MediaQuery .of(context).size.height + 1000,

then this works fine I can scroll down until the bottom of gridview and even further so have a lot of white space.

What is the proper fix to: Have only scrollbar for the entire _buildBody Widget, so when I scroll down also the title scrolls down and I can go until the bottom of the gridview. With my current approach the problem is that don't know the height beforehand so singlechildscrollbar is not working well

I uploaded some illustrative videos as well to explain easier. The default behaviour which of course is not a bug and works as intended, the title does not scroll. https://www.youtube.com/shorts/uRBUO49XM6E I want to be able to scroll also the title when scroll down the grid items.


Solution

  • For that you don't need the heigh, just remove Flexible and Container's height and add shrinkWrap: true to GridView, like this:

    SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Text('Some title'),
                const SizedBox(
                  height: 16,
                ),
                GridView.count(
                    primary: false,
                    physics: NeverScrollableScrollPhysics(),
                    crossAxisSpacing: 8,
                    mainAxisSpacing: 8,
                    crossAxisCount: 2,
                    shrinkWrap: true,
                    children: List<Widget>.generate(data.length,
                            (index) => _buildItem(index, data[index])),
                ),
              ],
            ),
          ),
        )