Slivers in Flutter - Part (1)

Slivers in Flutter - Part (1)

What is Sliver? What is CustomScrollView? An In-depth Explanation of SliverList and SliverAppBar with Example.

Dhruv Nakum
ยทSep 10, 2021ยท

6 min read

Subscribe to my newsletter and never miss my upcoming articles

Listen to this article

Sliver

  • Slivers are basically a scrollable area, that can be customized. Slivers help us to make the scrolling fancier instead of a normal boring scroll.
  • Slivers are useful for placing multiple scrollable widgets (ListView, GridView) inside it. It means we can handle nested scroll view. Like below -
  • nested_scroll_view.gif
  • In-fact, scrollable widgets like ListView, GridView, SingleChildScrollView, etc are implementing slivers under the hood.

CustomScrollView

  • If you want to use different Slivers, you need a special widget called CustomScrollView. All the slivers are placed inside it.
  • CustomScrollView is the Widget that allows different types of scrollable widgets and lists. And these scrollable lists and widgets are called slivers.
  • There are several types of slivers available. For example - SliverAppBar, SliverGridList, and SliverList, etc.

    One thing to note here is CustomScrollView only takes Slivers Widgets as a child. Normal widgets like Container, ListTile, etc will not work.

  • Example :
  • Scaffold(
    body: CustomScrollView(
      slivers: [
          SliverAppBar(/**/), 
          SliverGridList(/**/),
          SliverList(/**/),
          //......
        ]
      ),
    );
    
  • The CustomScrollView has many properties and one of them is slivers. Which takes list slivers as an input.
  • Let's first understand different slivers one by one with an example. And then we can define those slivers inside the CustomScrollView.

SliverList

  • The SliverList is a widget that takes lists of items as child, same as ListView and GridView.
  • This is useful, If you have a ListView and GridView and you want to scroll it together. Like below -
  • list_grid_scroll.gif
  • SliverList, has one parameter called delegate. There are two types of delegate -
  • SliverChildListDelegate: Takes a list of widgets that we want to display. Widgets defined in this list will be rendered at once. There will not be any lazy loading.
  • SliverChildBuilderDelegate: Take a list of widgets that will be created lazily. It means as the user scrolls items get rendered.
  • Scaffold(
        body: CustomScrollView(
        slivers: [
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                return Container(
                  height: 50,
                  alignment: Alignment.center,
                  color: index.isEven ? Colors.grey : Colors.amberAccent,
                  child: Text('List item :  $index'),
                );
              },
              childCount: 12,
            ),
          ),
        ],
    ));
    

SliverAppBar

  • This is the same as the AppBar widget, the difference is that it works with CutomScrollView.
  • It means it has all the properties like - title, actions, leading, flexibleSpace etc.
  • But it has some additional parameters like pinned, floating, snap, expandedHeight which customizes the behavior of the AppBar. Let's see how these properties affect the scroll behavior, in the below example.
  • Creating SliverAppBar with title and action
    Scaffold(
        body: CustomScrollView(
        slivers: [
          SliverAppBar(
            title: Text('Hello Sliver'),
            actions: <Widget>[
              IconButton(
                icon: const Icon(Icons.settings),
                onPressed: () {/* ... */},
              ),
            ],
          )
        ],
     )
    );
    
  • Output:
  • sliver_app_bar.png
  • As you can see this looks like a traditional material app AppBar.
  • Let's understand the different properties of SliverAppBar:

    expandedHeight:

  • This defines the size of the AppBar when fully expanded.
  • Example:
  • SliverAppBar(
            expandedHeight: 200,
            title: Text('Hello Sliver'), 
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • The height will get shrink as the user scrolls down, like below -
  • list_grid_scroll.gif
  • But if you see, The AppBar hides when the user scrolls down. Let's pin the AppBar.

pinnned:

  • This will determine, whether the AppBar remains visible on the screen when the user scrolls down or not.
  • If true: AppBar will not hide on scroll
  • SliverAppBar(
            expandedHeight: 200,
            pinned: true,
            title: Text('Hello Sliver'), 
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • pinned_example.gif

floating:

  • If true, then the AppBar will get visible as soon as the user scrolls towards the AppBar.
  • If false then the user has to scroll all the way to the top in order to access AppBar
  • SliverAppBar(
            expandedHeight: 200,
            floating:true
            title: Text('Hello Sliver'), 
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • floating_true.gif

snap:

  • If true, Then the whole AppBar will be visible whenever a user tries to scroll toward the AppBar.
  • The floating value must have true in order to run snap.
    SliverAppBar(
            expandedHeight: 200,
            floating:true,
            snap: true,
            title: Text('Hello Sliver'), 
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • snap_true.gif
  • Difference between snap and floating is, snap shows the AppBar at once, whereas the floating shows AppBar as the user scrolls up.
  • floating_snap_difference.gif

You can try different combinations of floating, pinned, and snap to get various results.

flexibleSpace

  • It is used to give a background and various collapseModes to the AppBar.
  • There is title property also. It is placed at the bottom. When the user scrolls up, it will transform its position with the transition.
  • For example -
  • SliverAppBar(
             flexibleSpace: FlexibleSpaceBar(
                        title: Text("Welcome to Space"),
                        background: Image.network("url",fit: BoxFit.cover),
             ),
            expandedHeight: 200,
            pinned: true,
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • flexible.gif
  • Isn't it looking awesome? When we scroll up we are getting parallax effect. And it's because of the collapseMode property.
  • The collapseMode has 3 mode - parallax, pin, none
  • If you put CollapseMode.pin then you will not get a parallax effect of the image. The image will simply change it's a position with AppBar and fades out, like below -
  • SliverAppBar(
             flexibleSpace: FlexibleSpaceBar(
                        collapseMode: CollapseMode.pin,
                        title: Text("Welcome to Space"),
                        background: Image.network("url",fit: BoxFit.cover),
             ),
            expandedHeight: 200,
            pinned: true,
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • collapsemode_pin.gif

stretch

  • Default value is false.
  • If you scroll down when you're at the top then you will see the empty space, like below -
  • stretch_false.gif
  • To fill the overflowing space when the user scrolls down, give stretch a value true.
  • SliverAppBar(
             stretch: true,
             flexibleSpace: FlexibleSpaceBar(
                        collapseMode: CollapseMode.pin,
                        title: Text("Welcome to Space"),
                        background: Image.network("url",fit: BoxFit.cover),
             ),
            expandedHeight: 200,
            pinned: true,
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • stretch.gif
  • You can also trigger a function when the user stretches by implementing onStretchTrigger function of SliverAppBar.

    Note: You have to provide scrollBehavior to the MaterialApp for the bouncing scrolling effect.

stretchModes

  • If you want to blur, or fade the image on the overflowing scroll instead of zooming, then you can provide different stretchModes inside the FlexibleSpaceBar.
  • It has 3 main modes - blurBackground, fadeTitle and zoomBackground (default)
  • Let's try the remaining 2 modes :
  • SliverAppBar(
             stretch: true,
             flexibleSpace: FlexibleSpaceBar(
                        collapseMode: CollapseMode.pin,
                        title: Text("Welcome to Space"),
                        background: Image.network("url",fit: BoxFit.cover),
                        stretchModes: [
                            StretchMode.fadeTitle,  // fades out the title 
                            StretchMode.blurBackground, // blur out the background
                            StretchMode.zoomBackground // zoom the background
                    ],
             ),
            expandedHeight: 200,
            pinned: true,
            actions: <Widget>[
            IconButton(
              icon: const Icon(Icons.settings),
              onPressed: () {/* ... */},
            ),
    ]),
    
  • stretchMode.gif

Wrapping Up

  • This is the Part - 1 of Advance Scrolling in Flutter.
  • In Part-2 we will see different types of Sliver and how to use them.
  • If you liked this article, share it with your developer friends and communities.
  • Comments and Feedback are welcomed ๐Ÿ˜ƒ
  • See you in the next article. Until then.....
  • PeaceOutImOutGIF.gif

Did you find this article valuable?

Support Dhruv Nakum by becoming a sponsor. Any amount is appreciated!

See recent sponsors |ย Learn more about Hashnode Sponsors
ย 
Share this