Dynamically managing content visibility is a common requirement in many Flutter applications. The ExpansionPanel widget provides an elegant solution by allowing users to expand or collapse sections of content. In this blog post, we'll explore the ExpansionPanel widget, its key attributes, and provide a comprehensive example to showcase its versatility.
The ExpansionPanel widget in Flutter facilitates the creation of collapsible and expandable panels that reveal or hide content based on user interaction. It is particularly useful when dealing with sections of content that can be toggled to conserve space or provide a focused view.
Attributes of ExpansionPanel:
headerBuilder (required):
- A callback function that builds the header widget for the panel.
body:
- The widget that represents the content of the panel.
isExpanded (required):
- A boolean value that determines whether the panel is initially expanded or collapsed.
canTapOnHeader:
- A boolean value that defines whether tapping on the header will expand or collapse the panel.
backgroundColor:
- The background color of the panel.
iconColor:
- The color of the expand/collapse icon.
iconPadding:
- The padding around the expand/collapse icon.
onExpansionChanged:
- A callback function that is triggered when the panel's expansion state changes.
Example: Let's create a Flutter app that uses the ExpansionPanel widget to display a list of items with expandable content.
import 'package:flutter/material.dart';
class myApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('ExpansionTile'),
),
body: ListView.builder(
itemBuilder: (BuildContext context, int index) => EntryItem(data[index]),
itemCount: data.length,
),
),
);
}
}
// One entry in the multilevel list displayed by this app.
class Entry {
Entry(this.title, [this.children = const <Entry>[]]);
final String title;
final List<Entry> children;
}
// The entire multilevel list displayed by this app.
final List<Entry> data = <Entry>[
Entry('Chapter A',
<Entry>[
Entry('Section A0',
<Entry>[
Entry('Item A0.1'),
Entry('Item A0.2'),
Entry('Item A0.3'),
],
),
Entry('Section A1'),
Entry('Section A2'),
],
),
Entry('Chapter B',
<Entry>[
Entry('Section B0'),
Entry('Section B1'),
],
),
Entry('Chapter C',
<Entry>[
Entry('Section C0'),
Entry('Section C1'),
Entry('Section C2',
<Entry>[
Entry('Item C2.0'),
Entry('Item C2.1'),
Entry('Item C2.2'),
Entry('Item C2.3'),
],
),
],
),
];
// Displays one Entry. If the entry has children then it's displayed
// with an ExpansionTile.
class EntryItem extends StatelessWidget {
const EntryItem(this.entry);
final Entry entry;
Widget _buildTiles(Entry root) {
if (root.children.isEmpty)
return ListTile(title: Text(root.title));
return ExpansionTile(
key: PageStorageKey<Entry>(root),
title: Text(root.title),
children: root.children.map<Widget>(_buildTiles).toList(),
);
}
@override
Widget build(BuildContext context) {
return _buildTiles(entry);
}
}
void main() {
runApp(myApp());
}