Search code examples
flutterlistviewflutter-listview

ListView with a single expanded tile at a time


I am trying to create a ListView widget that contains ExpansionTiles and I want to have only a single tile expanded at a time. I am using quite a bit of data, so I am using ListView.builder I am getting an error:

Error: Assertion failed:
_state != null

Documentation also specifies that you cannot call controller methods inside a build method.

My code looks like this:

return ListView.builder(
          itemCount: data.length,
          itemBuilder: (context, index) {
            return ExpansionTile(
              controller: expansionControllers[index],
              leading: Text(data[index].code),
              title: Text(data[index].name),
              onExpansionChanged: (value) async {
                if (value) {
                  setState(() {
                    prevIndexExpanded = index;
                  });

                  //Do stuff
                }
              },
              children: [...]
            );
          },
        );

where I have a prevIndexExpanded which tracks the currently expanded tile and I have generated a list of ExpansionTileController() for each tile.

final expansionControllers = List.generate(
          data.length,
          (index) => ExpansionTileController(),
        );

So to be clear: when selecting a tile it should expand and if there is another already expanded tile, it should collapse, so there is only one expanded at a time.


Solution

  • As it turns out, I was making the mistake of generating the list inside of the build method of the Widget, therefore it was generating a new list on every rebuild and the controllers wouldn't match. After taking it outside, everything is working as expected.

    Quick note: If you are using a ListView.builder with a lot of ExpansionTiles, you should specify the initiallyExpanded property, since while scrolling, the ListView rebuilds and it will collapse expanded tiles otherwise.