image

07 Jan 2026

9K

35K

Building a Collapsible Header Widget with SliverAppBar in Flutter

In Flutter, creating dynamic and responsive UIs is key to delivering a great user experience. A common pattern for improving navigation and visual appeal is the "collapsible header" – an app bar that expands and collapses as the user scrolls through content. This article will guide you through building such a widget using Flutter's powerful SliverAppBar, a flexible component designed specifically for scrollable effects.

Understanding Slivers and CustomScrollView

Before diving into SliverAppBar, it's essential to grasp the concept of "slivers." Slivers are scrollable portions of a scroll view. Unlike traditional widgets that are aware of their full size, slivers only render the visible portion, making them highly performant for long lists. To combine multiple slivers (like an app bar and a list), Flutter provides the CustomScrollView widget.

CustomScrollView takes a list of slivers as its children, allowing you to create complex scrolling effects where different parts of the scroll view behave independently.

Implementing the Collapsible Header with SliverAppBar

The SliverAppBar is a specialized app bar that integrates seamlessly into a CustomScrollView. It allows for a rich variety of collapsing and expanding behaviors. Let's start with a basic setup.

Basic Structure

Every collapsible header setup begins with a CustomScrollView containing a SliverAppBar and at least one other scrollable sliver (like SliverList or SliverGrid) to provide content to scroll against.


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Collapsible Header Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const CollapsibleHeaderPage(),
    );
  }
}

class CollapsibleHeaderPage extends StatelessWidget {
  const CollapsibleHeaderPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            expandedHeight: 200.0, // The height of the app bar when it's fully expanded.
            flexibleSpace: FlexibleSpaceBar(
              title: const Text('Collapsible Header'),
              background: Image.network(
                'https://picsum.photos/id/1084/400/300', // Example image
                fit: BoxFit.cover,
              ),
            ),
            pinned: true, // The app bar stays at the top when scrolled up.
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  color: index.isOdd ? Colors.white : Colors.blueGrey[50],
                  height: 100.0,
                  child: Center(
                    child: Text('Item $index', style: const TextStyle(fontSize: 20)),
                  ),
                );
              },
              childCount: 50, // Number of list items
            ),
          ),
        ],
      ),
    );
  }
}

Key SliverAppBar Properties

Let's break down the essential properties of SliverAppBar:

  • expandedHeight: This required property defines the height of the app bar when it's fully expanded. When the user scrolls, the app bar will collapse from this height down to its toolbarHeight (which defaults to 56.0).
  • flexibleSpace: This widget is placed behind the toolbar and can be animated as the app bar expands and collapses. It's typically where you'd put large images, titles, or other decorative elements using a FlexibleSpaceBar.
  • pinned: If set to true, the app bar will remain visible at the top of the screen (at its toolbarHeight) even after it has fully collapsed. If false, it will scroll completely off-screen.
  • floating: When true, the app bar will immediately reappear when the user scrolls down, even if they haven't scrolled all the way to the top of the content.
  • snap: This property works in conjunction with floating: true. If true, the app bar will snap fully open or fully closed when the user stops scrolling, rather than stopping halfway.
  • bottom: A PreferredSizeWidget that appears at the bottom of the app bar. Useful for adding tabs (e.g., TabBar) that should collapse with the app bar.

Enhancing FlexibleSpace with FlexibleSpaceBar

The FlexibleSpaceBar is designed to be used within SliverAppBar's flexibleSpace property. It provides built-in behaviors for animating its child widgets, such as parallax effects for its background and fading/scaling for its title.


FlexibleSpaceBar(
  title: const Text('My Awesome Header'),
  centerTitle: true,
  background: Image.network(
    'https://picsum.photos/id/1005/800/600',
    fit: BoxFit.cover,
  ),
  collapseMode: CollapseMode.parallax, // Adds a parallax effect to the background
),

Adding Different Scrollable Content

Beyond SliverList, you can use other slivers for your main content:

  • SliverGrid: For displaying items in a grid layout.
  • SliverToBoxAdapter: To adapt a single non-sliver widget (like a Column or Container) into a sliver. This is useful for placing static content that doesn't need to be scrollable within the CustomScrollView.

Example with floating and snap

To illustrate the effect of floating and snap, modify the SliverAppBar as follows:


SliverAppBar(
  expandedHeight: 200.0,
  flexibleSpace: FlexibleSpaceBar(
    title: const Text('Floating & Snapping'),
    background: Image.network(
      'https://picsum.photos/id/1018/400/300',
      fit: BoxFit.cover,
    ),
  ),
  pinned: false,   // It will scroll off-screen completely
  floating: true,  // Immediately reappears on scroll down
  snap: true,      // Snaps open/closed
),

Complete Example

Here's a full runnable example demonstrating a typical collapsible header setup with an image background, a title, and a scrollable list.


import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Collapsible Header Demo',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: const CollapsibleHeaderPage(),
    );
  }
}

class CollapsibleHeaderPage extends StatelessWidget {
  const CollapsibleHeaderPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            expandedHeight: 250.0,
            floating: false,
            pinned: true,
            flexibleSpace: FlexibleSpaceBar(
              centerTitle: true,
              title: const Text('My Awesome Collapsible Header',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20.0,
                    fontWeight: FontWeight.bold,
                  )),
              background: Image.network(
                'https://picsum.photos/id/1060/800/600',
                fit: BoxFit.cover,
              ),
            ),
          ),
          SliverToBoxAdapter(
            child: Padding(
              padding: const EdgeInsets.all(16.0),
              child: Card(
                elevation: 4,
                child: Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Text(
                    'Welcome to our collapsible header example! Scroll down to see the magic happen.',
                    style: TextStyle(fontSize: 18),
                  ),
                ),
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  height: 80.0,
                  color: index.isOdd ? Colors.white : Colors.teal[50],
                  alignment: Alignment.center,
                  child: Text(
                    'List Item ${index + 1}',
                    style: const TextStyle(fontSize: 18),
                  ),
                );
              },
              childCount: 40,
            ),
          ),
        ],
      ),
    );
  }
}

Conclusion

The SliverAppBar in Flutter, when combined with CustomScrollView, offers a powerful and flexible way to create engaging collapsible headers. By mastering properties like expandedHeight, flexibleSpace, pinned, floating, and snap, you can design highly interactive and visually appealing app bars that enhance the user experience. Experiment with different combinations to achieve the precise scrolling effects your application needs.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is