flutter

Flutter Expansion Panel Widget Complete Guide

Creating a expansion panel widget in Flutter

The expansion panel is a useful widget if you have a set of items that contain the main part that needs to show always and the subpart like description which is not required to show always.

For example, let’s say we have a list of Cars and their details and we need to show the car details on the list. This cannot be done using an ordinary list view and if we show the car and the description always it will take more space of the list for single items. Therefore we can use the Expansion panel widget to showing this kind of item. You can add Car name as a tile of the panel and hide the description and show only when the user clicks each item.

Before implementing the Expansion panel list let’s discuss what is the widget we are going to use in the implementation

ExpansionPanel Widget

ExpansionWidget can be considered as one single item in the list. There are mainly a few properties that need to be discussed.

isExpanded – this property accepts a boolean value and based on that panel decide whether the need to expand or not

headerBuilder – This is the widget builder which can be used to build the header of the expansion panel. This section will be always visible regardless of whether the widget is in an expanded state or not.

child – For the child property, we can provide the widget need to show when expanded.

ExpansionPanelList Widget

For the expansion panel list widget, we can provide a list of ExpansionPanel widget and it shows those same as the ListView widget. But there are some properties which is available in the ExpansionPanelList which make it special.

expansionCallback – This the most important property which is available and this callback will trigger when the user expands a single Panel. In here there are two argument which you can access. First one is panel index which is user clicked and the second one is the currently expanded or not state.

Using those values we should manually handle the expansion state and it will not done by the widget itself automatically

Handle expansion panel Open and Close Status

As we discussed initially let’s take the same car example. First Create a Car class in which we can set car name, description and expanded state.

class Car{
      int id;
      String name;
      String description;
      bool isExpanded;
    
      Car(this.id,this.name,this.description,this.isExpanded);
    }

After that let’s create a List of Car object which need to show in the List.

 List<Car> cars = [
            Car(1,"Benz","This is the benz description",false),
            Car(2,"Audi","This is the Audi description",false)
      ];

Now you have list of cars which need to show. Now let’s create an expansion panel list.

Let’s create a ExpansionPanelList widget and there are mainly two properties that need to set. As I said previously there are expansionCallback and the children property.

For the children, let’s try to create a List of ExpansionPanel using the list which we created previously. For that we can use map method in list to convert the List Object into an Expansion Panel items.

children: cars.map((car) { 
             return ExpansionPanel(
              isExpanded: car.isExpanded,
              headerBuilder: (bc,status){
    	          return Container(child: Container(
    	            padding: EdgeInsets.all(10),
    		          child: Text(car.name)),);
    		      },
    	        body: Container(
    	          padding: EdgeInsets.all(10),
    	          height: 100, child: Text(car.description)
    	        )
          );}
        ).toList()

Now when you run the application you can see the list with panel items. In because we set the second element as an expanded, you can see that show as an expanded and the other one show as a collapsed. But when you press the item it does not get expanded.

For that we need to implement the expansionCallback to handle that scenario. inside the expansionCallback you can access the list of cars and the clicked index and current expanded status. Therefore we can get the car object from the List and change the object status like below.

expansionCallback: (panelIndex,isExpand){
    setState(() {
       cars[panelIndex].isExpanded = !isExpand;
    });
},

Now you can run the app again and see the expansion functionality works expectedly.

Change Expansion Panel background colour

You can change the ExpansionPanel background colour by setting the colour property of the body Container. But there is a small issue the container show as align centre and it does not take full available space of the body. To solve that you can change the container width to take full available space by using MediaQuery.

Different between ExpansionPanelList and ExpansionPanelList.radio

ExpantionPanelList allows expanding more than one panel at a time. If you want to create a list that allows only to expand one list item, you should use the radio constructor in the ExpansionPanelList.

Also instead of ExpansionPanel widget, you should use ExpansionPanelRadio for this implementation. The properties are slightly different in the ExpansionPanelRadio widget. There is no is isExpanded property. Then how can we expand and collapse the Widget? Actually, it will handle that by itself and we do not need to worry about that. But there is another property called value which needs to be set. That value will be used to track the widget and that must be unique for the single Widget.

In the previous example, we have added id for each car and you can use that property to identify each car uniquely.

class _ExpansionWidState extends State<ExpansionWid> {

  List<Car> cars = [
    Car(1,"Benz","This is the benz description",false),
    Car(2,"Audi","This is the Audi description",false)
  ];

  @override
  Widget build(BuildContext context) {
    return ExpansionPanelList.radio(
      expansionCallback: (panelIndex,isExpand){
        setState(() {
          cars[panelIndex].isExpanded = !isExpand;
        });
      },

      children: cars.map((car) { 
         return ExpansionPanelRadio(
          value: car.id,
          headerBuilder: (bc,status){
          return Container(child: Container(
            padding: EdgeInsets.all(10),
          child: Text(car.name)),);
        },
        body: Container(
          color: Colors.cyan,
          padding: EdgeInsets.all(10),
          width: MediaQuery.of(context).size.width,
          height: 100, child: Text(car.description)
          )
      );}
    ).toList());
  }
}

Change the animation duration

Expand and Collapse animation duration can be changed using the animationDuration property in the ExpansionPanelList widget

ExpansionPanelList(
      animationDuration: Duration(seconds: 1),
)

Expand the Panel in Initial Load

ExpansionPanelList radio contractor allows you to set the initial expanded view and you can pass the panel id, in this scenario car id and make it expanded in the load.

 ExpansionPanelList.radio(
          initialOpenPanelValue: 2,
    )

Change the ExpansionPanel divider colour

Panel divide color can be changed by setting dividerColor property to the ExpansionPanelList widget

ExpansionPanelList.radio(
          dividerColor: Colors.red
    )

Physical Address

304 North Cardinal St.
Dorchester Center, MA 02124