Geek Culture
Published in

Geek Culture

Dynamically Pinned List Headers

A Flutter Package Spotlight

Flutter provides a powerful solution to implement advanced scrolling in the form of Slivers. As noted in the Flutter documents, a Sliver is a portion of a scrollable area that you can define to behave in a special way. This allows us to combine multiple scrollable widgets (ListView, GridView, etc.) into a single scrollable widget where they scroll in unison, as seen in the following video.

It also allows us to implement advanced features like expanding/collapsing AppBars, as demonstrated below.

However, the Slivers library leaves a few things to be desired. For example, did you notice the headers being pinned 22 seconds into the first video? They just stack upon one another like in the demo below.

There is no easy way to dynamically pin the headers as the list scrolls, replacing the currently pinned header with the one below. I set out to create a solution that could handle this, but then I discovered that another member of the Flutter community had already taken care of it! 😃 So instead of writing an article on how I implemented the solution, I get to highlight the amazing sliver_tools package from Pieter Vanloon! Let’s take a look at how to use it.

This package provides a number of widgets that are helpful in extending Flutter’s advanced scrollable UI capabilities. We will be using two of them: MultiSliver and SliverPinnedHeader.

First, let’s create a Section widget that extends MultiSliver. We will accept parameters to define the header color, title, title color, and a list of items to be displayed below it. Then we will pass a SliverPinnedHeader and SliverList as children to our super constructor.

class Section extends MultiSliver {
Key? key,
required String title,
Color headerColor = Colors.white,
Color titleColor =,
required List<Widget> items,
}) : super(
key: key,
pushPinnedChildren: true,
children: [
child: ColoredBox(
color: headerColor,
child: ListTile(
textColor: titleColor,
title: Text(title),
delegate: SliverChildListDelegate.fixed(items),

The important thing to note here is the pushPinnedChildren parameter. Setting this to true provides the behavior we want. If it is false, the headers will behave exactly as they did with Flutter’s Slivers.

Now, let’s use our Section widget in a CustomScrollView.

slivers: [
title: 'Category #1',
items: List.generate(10, (index) => ListTile(
title: Text('Item #${index + 1}'),
title: 'Category #2',
items: List.generate(10, (index) => ListTile(
title: Text('Item #${index + 11}'),

For brevity, I have only shown the code for 2 sections, but you can create as many as you want. Let’s see how it looks.

That’s much better! As you can see, the pinned headers are replaced smoothly as we scroll through our sections. For a fun time, try replacing SliverPinnedHeader with a collapsing SliverAppBar and see what you can come up with!

As always, thank you for reading! If you found this article helpful, please clap and follow to keep up with my work with Flutter and more. Questions & comments are welcome as well.




A new tech publication by Start it up (

Recommended from Medium

Sync MySQL with Elasticsearch

LDAPs Certificate in Spring Boot Application and its Docker Image

ClickHouse + Kafka = ❤

Easy approach for implementing CI/CD using Jenkins-Part 1

Build Docker Base Images From Scratch Using Distroless

An illustration of the Docker and Deno mascots

Best Practices for Microservice

Using Heroku to Quickly Build a Multi-Tenant SaaS Startup (Part 1)

What is Git? How to use Git commands?

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Lee Phillips

Lee Phillips

Software developer. Flutter fanatic. Other interests include photography, sports, coffee, and food.

More from Medium

Timer Precision in Flutter

Building Custom TabBar Indicator in Flutter

How to publish your flutter app to apple store, TestFlight?

Pull down to REFRESH in Flutter