ExapansionPanel

ExpansionPanel Widget – Flutter Guide By Flutter Agency

Flutter has a really good widget to achieve expand/collapse functionality. It has ExpansionPanelList & ExpansionPanel to create an expand/collapse view. As we know in Flutter everything is a widget and hence Flutter ExpansionPanel is also a widget that you can use like other Flutter widgets.

What is ExpansionPanel Widget?

ExpansionPanel Widget is a list that shows its children using expansion animation on click of item.

The constructor of ExpansionPanel will look like below :

 ExpansionPanelList(
{Key? key,
List<ExpansionPanel> children = const <ExpansionPanel>[],
ExpansionPanelCallback? expansionCallback,
Duration animationDuration = kThemeAnimationDuration,
EdgeInsets expandedHeaderPadding = _kPanelHeaderExpandedDefaultPadding,
Color? dividerColor,
double elevation = 2}
)

Properties :

  • expansionCallBack : expansionCallBack gets called whenever the expand/collapsed button is pressed on any of the items inside the list. It gives us two things.

  1. Index of the clicked item
  2. Whether to expand or collapsed the item clicked.

  • children : ExpansionPanel Widget is used as a child for the ExpansionPanelList. This widget has got below properties.

  1. headerBuilder: Used to show the header of the item.
  2. body: Used to show the details of the item when expanded.
  3. isExpanded: This is very important as it decides whether to expand/collapsed the item or not. Defaults to false.
  4. canTapOnHeader: Be default, You have to click on the ^ icon to expand but you can pass true to this property to also make the header of the item clickable

  • animationDuration: Used to define the duration in which the expand and collapsed animation should complete. It defaults to 200ms.

However, it is recommended to keep it to the original you can still change it to anything like this.

animationDuration: Duration(milliseconds: 300),

Example :

Create a prepareData Array that will hold the data for the item. bool isExpanded will be used to determine whether the item needs to expand or not.

List<ItemModel> prepareData = <ItemModel>[
  ItemModel(
    header: 'Milk',
    bodyModel: BodyModel(price: 20, quantity: 10),
  ),
  ItemModel(
    header: 'Coconut',
    bodyModel: BodyModel(price: 35, quantity: 5),
  ),
  ItemModel(
    header: 'Watch',
    bodyModel: BodyModel(price: 800, quantity: 15),
  ),
  ItemModel(
    header: 'Cup',
    bodyModel: BodyModel(price: 80, quantity: 150),
  )
];

Prepare a list of items using Code Snippet as below :

headerBuilder: (BuildContext context, bool isExpanded) {
                    return Container(
                      padding: EdgeInsets.all(10),
                      child: Text(
                        prepareData[index].header,
                        style: TextStyle(
                          color: Colors.black54,
                          fontSize: 18,
                        ),
                      ),
                    );
                  },
isExpanded: prepareData[index].isExpanded,

 On receiving expansionCallback change the isExpanded parameter of the item inside the list of books and rebuild a widget.

expansionCallback: (int item, bool status) {
                setState(() {
                  prepareData[index].isExpanded =
                      !prepareData[index].isExpanded;
                });
              },

The complete Source code will look like the below :

import 'package:flutter/material.dart';
void main() {
  runApp(const MyApp());
}
class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}
class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
  List<ItemModel> prepareData = <ItemModel>[
    ItemModel(
      header: 'Milk',
      bodyModel: BodyModel(price: 20, quantity: 10),
    ),
    ItemModel(
      header: 'Coconut',
      bodyModel: BodyModel(price: 35, quantity: 5),
    ),
    ItemModel(
      header: 'Watch',
      bodyModel: BodyModel(price: 800, quantity: 15),
    ),
    ItemModel(
      header: 'Cup',
      bodyModel: BodyModel(price: 80, quantity: 150),
    )
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("ExpansionPanelList"),
      ),
      body: Container(
        padding: const EdgeInsets.all(10),
        child: ListView.builder(
          itemCount: prepareData.length,
          itemBuilder: (BuildContext context, int index) {
            return ExpansionPanelList(
              children: [
                ExpansionPanel(
                  body: Container(
                    padding: const EdgeInsets.all(10),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: <Widget>[
                        Text(
                          'PRICE: ${prepareData[index].bodyModel.price}',
                          style: TextStyle(
                            color: Colors.grey[700],
                            fontSize: 18,
                          ),
                        ),
                        Text(
                          'QUANTITY: ${prepareData[index].bodyModel.quantity}',
                          style: TextStyle(
                            color: Colors.grey[700],
                            fontSize: 18,
                          ),
                        )
                      ],
                    ),
                  ),
                  headerBuilder: (BuildContext context, bool isExpanded) {
                    return Container(
                      padding: const EdgeInsets.all(10),
                      child: Text(
                        prepareData[index].header,
                        style: const TextStyle(
                          color: Colors.black54,
                          fontSize: 18,
                        ),
                      ),
                    );
                  },
                  isExpanded: prepareData[index].isExpanded,
                )
              ],
              expansionCallback: (int item, bool status) {
                setState(() {
                  prepareData[index].isExpanded =
                      !prepareData[index].isExpanded;
                });
              },
            );
          },
        ),
      ),
    );
  }
}
class ItemModel {
  String header;
  BodyModel bodyModel;
  bool isExpanded;
  ItemModel({
    this.header = '',
    required this.bodyModel,
    this.isExpanded = false,
  });
}
class BodyModel {
  int price;
  int quantity;
  BodyModel({
    this.price = 0,
    this.quantity = 0,
  });
}

In the above code snippet, we have used a ListView Widget. We will get output like below:

Expansion Panel

ExpansionPanel List

Thanks for being with us !!!

Keep reading !!!

FlutterAgency.com is our portal Platform dedicated to Flutter Technology and Flutter Developers. The portal is full of cool resources from Flutter like Flutter Widget Guide, Flutter Projects, Code libs and etc.

FlutterAgency.com is one of the most popular online portal dedicated to Flutter Technology and daily thousands of unique visitors come to this portal to enhance their knowledge on Flutter.

Nirali Patel

Written by Nirali Patel

Nirali Patel is a dedicated Flutter developer with over two years of experience, specializing in creating seamless mobile applications using Dart. With a passion for crafting user-centric solutions, Nirali combines technical proficiency with innovative thinking to push the boundaries of mobile app development.

Leave a comment

Your email address will not be published. Required fields are marked *


ready to get started?

Fill out the form below and we will be in touch soon!

"*" indicates required fields

✓ Valid number ✕ Invalid number
our share of the limelight

as seen on