Search code examples
flutterdartpaddingmargin

Flutter NestedScrollView with SliverAppBar Leaves Extra Space Underneath


Title:

Flutter NestedScrollView with SliverAppBar Leaves Extra Space Underneath

Body:

I'm using a NestedScrollView with a SliverAppBar that has a search bar as its title. The app bar collapses correctly, but there’s extra white space underneath it when scrolling.

Code Snippet:

Scaffold(
  body: NestedScrollView(
    floatHeaderSlivers: true,
    headerSliverBuilder: (context, innerBoxIsScrolled) => [
      SliverAppBar(
        floating: true,
        toolbarHeight: kToolbarHeight,
        title: Searchbar(
          searchController: _searchController,
          filterItems: _filterItems,
        ),
      ),
    ],
    body: SafeArea(
      child: GridView.builder(
        padding: const EdgeInsets.all(10),
        itemCount: filteredItems.length,
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
          childAspectRatio: 1.2,
        ),
        itemBuilder: (BuildContext context, int index) {
          final item = filteredItems[index].data() as Map<String, dynamic>;
          return Card(
            child: Padding(
              padding: const EdgeInsets.all(12.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Text(item['Data'] ?? 'No Data'),
                  Text('Category: ${item['Category'] ?? 'Unknown'}'),
                ],
              ),
            ),
          );
        },
      ),
    ),
  ),
);

What I’ve Tried:

  • Removing SafeArea (worked, caused content to overlap the status bar).

How can I remove the extra space without breaking the layout?

app bar with empty space underneath it


Solution

  • The issue in your code coming from the default top padding in the GridView widget. To resolve this, do this:

    1. Remove the SafeArea widget from around the GridView.
    2. Adjust the padding of the GridView by overriding its default padding.

    Before : padding: const EdgeInsets.all(10),

    After : padding: const EdgeInsets.only(top: 0, right: 10, left: 10, bottom: 10),

    You can also change the value of the expandedHeight to reduce the expanded Height of the SliverAppBar widget <------ expandedHeight: 0.0,

    For the SafeArea widget, you can wrap the Scaffold or NestedScrollView with it, but avoid wrapping the GridView directly with SafeArea. This ensures proper spacing without interfering with the GridView's layout.

    Full Code After Overriding:

    SafeArea(      <--------- Move to Here
      child: Scaffold(
        body: NestedScrollView(  <-------- Or Move to Here
          floatHeaderSlivers: true,
          headerSliverBuilder: (context, innerBoxIsScrolled) => [
            SliverAppBar(
              floating: true,
              toolbarHeight: kToolbarHeight,
              expandedHeight: 0.0,
              backgroundColor: Colors.amber,
              title: Searchbar(
                searchController: _searchController,
                filterItems: _filterItems,
              ),
            ),
          ],
          body: GridView.builder(
            padding: const EdgeInsets.only(
              top: 0,          <------- Use the top padding you want
              right: 10,
              left: 10,
              bottom: 10,
            ),
            itemCount: 8,
            gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 2,
              crossAxisSpacing: 10,
              mainAxisSpacing: 10,
              childAspectRatio: 1.2,
            ),
            itemBuilder: (BuildContext context, int index) {
              final item = filteredItems[index].data() as Map<String, dynamic>;
              return Card(
                child: Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(item['Data'] ?? 'No Data'),
                      Text('Category: ${item['Category'] ?? 'Unknown'}'),
                    ],
                  ),
                ),
              );
            },
          ),
        ),
      ),
    );