Flutter: Adding a Header to a ListView

Last updated on January 25, 2021 A Goodman Loading... Post a comment

At this time, the ListView widget doesn’t come with an out of the box option that lets us create a header section. However, we can make a beautiful header within a few lines of code.

Strategies

There are several ways to add a header:

Unfixed header

The header acts like a list item and it will become invisible when scrolling down.

In this case, what we need to do is to return an extra widget when index = 0, as below:

body: ListView.builder(
            itemCount: // The length,
            itemBuilder: (_, index) {
              if (index == 0) {
                return Column(
                  children: [
                    // The header
                    Container(
                     
                    ),

                    // The fist list item
                    _listItem(index)
                  ],
                );
              }
              // If index != 0
              return _listItem(index);
})

Please check the example 1 for more clarity.

Fixed header

The header is always on top of the ListView.

In this case, we nest the ListView inside an Expanded widget then wrap this Expanded widget and our custom header with a Column widget, like this:

body: Column(
          children: [
            Container(
              // The header will be here
            ),
            Expanded(
              // The ListView
              child: ListView.builder(
                  itemCount: // The length,
                  itemBuilder: (_, index) {
                    return //List Item Widget Here
                  }),
            ),
          ],
)

Please check the example 2 for better understanding.

Note: The Expanded widget is necessary because it will prevent the error “Vertical viewport was given unbounded height” that occurs when a ListView is a child of a Column.

Example 1 – Unfixed Header Bar

Preview

As you can see, the header will become invisible when scroll down.

The full code:

// main.dart
import 'package:flutter/material.dart';
import 'dart:math';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Generate dummy data to feed the list view
  final List _peopleData = List.generate(1000, (index) {
    return {"name": "Person \#$index", "age": Random().nextInt(90) + 10};
  });

  // Item of the ListView
  Widget _listItem(index) {
    return Container(
      padding: const EdgeInsets.all(10),
      child: ListTile(
        leading: Text(index.toString(), style: TextStyle(fontSize: 18)),
        title: Text(
          _peopleData[index]['name'].toString(),
          style: TextStyle(fontSize: 18),
        ),
        trailing: Text(_peopleData[index]['age'].toString(),
            style: TextStyle(fontSize: 18, color: Colors.purple)),
      ),
      decoration: BoxDecoration(
          border: Border(bottom: BorderSide(width: 1, color: Colors.black26))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Kindacode.com'),
        ),
        body: ListView.builder(
            itemCount: _peopleData.length,
            itemBuilder: (_, index) {
              if (index == 0) {
                return Column(
                  children: [
                    // The header
                    Container(
                      padding: const EdgeInsets.all(10),
                      color: Colors.amber,
                      child: ListTile(
                        leading: Text('ID'),
                        title: Text('Name'),
                        trailing: Text('Age'),
                      ),
                    ),

                    // The fist list item
                    _listItem(index)
                  ],
                );
              }
              return _listItem(index);
            }));
  }
}

Example 2 – Fixed Header

Preview

The header stays on top forever.

The full code

// main.dart
import 'package:flutter/material.dart';
import 'dart:math';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Kindacode.com',
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // Generate dummy data to feed the list view
  final List _peopleData = List.generate(1000, (index) {
    return {"name": "Person \#$index", "age": Random().nextInt(90) + 10};
  });

  // Item of the ListView
  Widget _listItem(index) {
    return Container(
      padding: const EdgeInsets.all(10),
      child: ListTile(
        leading: Text(index.toString(), style: TextStyle(fontSize: 18)),
        title: Text(
          _peopleData[index]['name'].toString(),
          style: TextStyle(fontSize: 18),
        ),
        trailing: Text(_peopleData[index]['age'].toString(),
            style: TextStyle(fontSize: 18, color: Colors.purple)),
      ),
      decoration: BoxDecoration(
          border: Border(bottom: BorderSide(width: 1, color: Colors.black26))),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text('Kindacode.com'),
        ),
        body: Column(
          children: [
            Container(
              padding: const EdgeInsets.all(10),
              color: Colors.amber,
              child: ListTile(
                leading: Text('ID'),
                title: Text('Name'),
                trailing: Text('Age'),
              ),
            ),
            Expanded(
              child: ListView.builder(
                  itemCount: _peopleData.length,
                  itemBuilder: (_, index) {
                    return _listItem(index);
                  }),
            ),
          ],
        ));
  }
}

Next Steps

We’ve walked through 2 example projects that contains a ListView which has a custom header section. If you would like to learn more about ListView, take a look at the following articles:

You can also check out our Flutter topic page or Dart topic page for the latest tutorials and examples.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

Related Articles