How to implement the Expansion Tile in Flutter

In this guide, we will learn how to implement the ExpansionTile in Flutter. A single-line ListTile with an expansion arrow icon that expands or collapses the tile to reveal or hide the children. This widget is typically used with ListView to create an “expand/collapse” list entry. This widget lets you create a detailed tile that can be used as part of a list view. We need to show some detailed information on the list for many applications, but for this, we do not have enough space to expand and collapse the list. Then we can create it with the extension tile widget.

Main Properties of Expansion Tile

title allows us to choose the title for the expansion tile widget and always be visible to the user.
children holds any number of widgets. which can be a card for a simple text and allowed only by clicking on the title of the widget.
leadingused on the first left side of the title, just as the leading list tile widget uses leading
backgroundColor background property gives color to the background of the expanded tile

Let’s take an example of how we can implement the Expanison Tile in our flutter application.

import 'package:flutter/material.dart';

class ExpansionScreen extends StatefulWidget {
  const ExpansionScreen({Key? key}) : super(key: key);

  @override
  State<ExpansionScreen> createState() => _ExpansionScreenState();
}

class _ExpansionScreenState extends State<ExpansionScreen> {
  final List<Map<String, dynamic>> dataItem = List.generate(
      50,
      (index) => {
            "id": index,
            "title": "Page Number $index",
            "content":
                "Page Number of $index has added on the book. It is very long and you have to expand the tile to see it."
          });
  void _removeItem(int id) {
    setState(() {
      dataItem.removeWhere((element) => element['id'] == id);
    });
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        backgroundColor: Colors.teal,
        behavior: SnackBarBehavior.floating,
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(15),
        ),
        duration: const Duration(milliseconds: 1000),
        content: Text('Item with id $id has been removed from the list')));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Expanison Tile'),
          centerTitle: true,
        ),
        body: ListView.builder(
            itemCount: dataItem.length,
            itemBuilder: (_, index) {
              final item = dataItem[index];
              return Card(
                // this key is required to save and restore ExpansionTile expanded state
                key: PageStorageKey(item['id']),
                // color: Colors.green,
                elevation: 4,
                child: ExpansionTile(
                  controlAffinity: ListTileControlAffinity.trailing,
                  childrenPadding:
                      const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
                  expandedCrossAxisAlignment: CrossAxisAlignment.end,
                  maintainState: true,
                  title: Text(item['title']),
                  // contents
                  children: [
                    Text(item['content']),
                    // This button is used to remove this item
                    TextButton.icon(
                      onPressed: () => _removeItem(item['id']),
                      icon: const Icon(Icons.delete),
                      label: const Text(
                        'Remove',
                      ),
                      style: TextButton.styleFrom(primary: Colors.red),
                    )
                  ],
                ),
              );
            }));
  }
}

Meanwhile, when we run this application in the emulator or device, we should get the UI similar to the screenshot below:

Get the full snippet for Expansition Tile in Flutter from here

Also read: Riverpod As An StateManagement: A Complete Guide