flutterdartflutter-sliver

Center `CustomScrollView` if has space


I have the folowing code:

    return Scaffold(
      body: CustomScrollView(
          physics: const AlwaysScrollableScrollPhysics(
            parent: BouncingScrollPhysics(),
          ),
          controller: controller,
          slivers: [
            SliverToBoxAdapter(
              child: Center(
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 64),
                  child: Text(
                    'Title',
                    style: theme.textTheme.titleLarge?.copyWith(
                      fontWeight: FontWeight.bold,
                      color: theme.colorScheme.onPrimary,
                    ),
                  ),
                ),
              ),
            ),
            SliverList.builder(
              itemCount: tiles.length,
              itemBuilder: (context, index) {
                final text = tiles[index];
                return Card(
                  margin: const EdgeInsets.symmetric(
                    horizontal: 24,
                    vertical: 8,
                  ),
                  child: ListTile(
                    title: Text(
                      text,
                      style: theme.textTheme.bodyLarge,
                    ),
                  ),
                );
              },
            ),
          ],
        ),
    );

This causes my layout output to be like this on my phone:

Current layout

What I wanted was a way of putting everything centred if all fit the screen, or else continue as is.

Centered

Is it possible to do anything similar with the use of Slivers? I wanted them because I would like that the title bounces and scrolls with the items when they're scrolled.


Solution

  • Similar to ListView, CustomScrollView has a shrinkWrap variable that when set to true will attempt to minimize the height of the scroll area.

    The default alignment for a scaffold is top left so once you shrink wrap the scroll view you will need to add the center widget as it's parent to get the center alignment you desire. The code looks like this:

    return Scaffold(
          body: Center(
            child: CustomScrollView(
              shrinkWrap: true,
              physics: AlwaysScrollableScrollPhysics(
                parent: BouncingScrollPhysics(),
              ),
              controller: controller,
              slivers: [
                SliverToBoxAdapter(
                  child: Center(
                    child: Padding(
                      padding: EdgeInsets.symmetric(vertical: 64),
                      child: Text(
                        'Title',
                        style: theme.textTheme.titleLarge?.copyWith(
                          fontWeight: FontWeight.bold,
                          color: theme.colorScheme.onPrimary,
                        ),
                      ),
                    ),
                  ),
                ),
                SliverList.builder(
                  itemCount: tiles.length,
                  itemBuilder: (context, index) {
                    final text = tiles[index];
                    return Card(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 24,
                        vertical: 8,
                      ),
                      child: ListTile(
                        title: Text(
                          text,
                          style: theme.textTheme.bodyLarge,
                        ),
                      ),
                    );
                  },
                ),
              ],
            ),
          ),
        );