expansion_tile_list 1.0.0
expansion_tile_list: ^1.0.0 copied to clipboard
ExpansionTileList is a Flutter widget that manages a list of expandable tiles, controlling their expansion behaviour and also simplifies the implementation of common features.
Expansion Tile List #
The ExpansionTileList widget is a container for the ExpansionTile widget that allows you to create a list of tiles.
It provides additional features that empowers you to customize the appearance of the tiles and control their expansion
programmatically.
Description #
The expansion_tile_list package provides a highly customizable list of expansion tiles for Flutter applications. It
allows developers to create lists of expandable tiles with various customization options for appearance, animations, and
control over the expansion state. The package supports features like global trailing widget, trailing animation, and
different expansion modes to suit various use cases.
Check out the demo page to explore the latest features and experience the features firsthand!”

Features #
List Features #
All the features affects all the tiles in the ExpansionTileList.
tileGapSizeallows you to specify the size of the gap between each tile in theExpansionTileList.trailingallows you to specify the trailing widget for all tiles, can be overridden byExpansionTiletrailing property.trailingAnimationallows you to specify a custom animation for the trailing widget.enableTrailingAnimationallows you to enable or disable the trailing animation.tileBuilderallows the customization of the creation and appearance of the tiles in theExpansionTileList.separatorBuilderallows the customization of the creation and appearance of the separators between the tiles in theExpansionTileList.initialExpandedIndexesallows you to specify the indexes of the tiles that are initially expanded.controllerallows you to programmatically control the expansion of the tiles.onExpansionChangedallows you to listen to the expansion changes of the tiles.ExpansionModeallows you to specify the expansion mode of theExpansionTileList. This feature can be used only with named constructor.ExpansionMode.atMostOneallows you to expand at most one tile at a time. (i.e zero or one )ExpansionMode.atLeastOneensures that at least one tile is always expanded (i.e one or more )ExpansionMode.exactlyOneallows you to expand exactly one tile at a time. (i.e one )ExpansionMode.anyallows you to expand any number of tiles. (i.e zero or more )
Item Features #
By default ExpansionTileList supports ExpansionTile widget as children to create tiles. But you can also use
ExpansionTileItem widget when more control is required. All the properties overrides the that of ExpansionTileList.
trailingallows you to specify the trailing widget for the tile.trailingAnimationallows you to specify a custom animation for the trailing widget.enableTrailingAnimationallows you to enable or disable the trailing animation.
Installation #
To use this package, add expansion_tile_list as
a dependency in your pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
expansion_tile_list: ^0.1.1
Usage #
Import the package:
import 'package:expansion_tile_list/expansion_tile_list.dart';
Example #
Here are some simple examples of how to use the ExpansionTileList: check out the demo
- Basic usage: create a list of
ExpansionTilewidgets using theExpansionTileListwidget.
import 'package:flutter/material.dart';
import 'package:expansion_tile_list/expansion_tile_list.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ExpansionTileList(
tileGapSize: 10.0,
children: <Widget>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[
Text('Child 1'),
],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[
Text('Child 2'),
],
),
],
),
),
);
}
}
- Using
trailingandtrailingAnimation: use thetrailingandtrailingAnimationproperties to customize the trailing widget of the tiles.
var expansionTileList =
ExpansionTileList(
trailing: Icon(Icons.arrow_drop_down),
trailingAnimation: ExpansionTileAnimation(
tween: Tween<double>(begin: 0, end: 0.5),
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut,
builder: (context, index, value, child) {
return Transform.rotate(
angle: value * pi,
child: child,
);
},
),
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
separatorBuilder: This property allows you to customize the appearance of the separators between the tiles in the list.
var expansionTileList =
ExpansionTileList(
separatorBuilder: (context, index, value, child) {
return Divider(
color: Colors.blue,
height: 2.0,
);
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
tileBuilder: This property allows you to customize the appearance of the tiles in the list.
var expansionTileList = ExpansionTileList(
tileBuilder: (context, index, isExpanded, child) {
return Container(
color: isExpanded ? Colors.blue : Colors.white,
child: child,
);
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
controller: This property allows you to programmatically control the expansion of the tiles.
var controller = ExpansionTileListController();
var expansionTileList = ExpansionTileList(
controller: controller,
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
_(){
/// Expand the first tile
controller.expand(0);
/// Collapse the first tilecontroller.collapse(0);
/// Toggle the first tilecontroller.toggle(0);
/// Expand all tilescontroller.expandAll();
/// Collapse all tiles
controller.collapseAll();
}
- Using
onExpansionChanged: This property allows you to listen to the expansion changes of the tiles.
var expansionTileList = ExpansionTileList(
onExpansionChanged: (index, isExpanded) {
print('Tile $index is ${isExpanded ? 'expanded' : 'collapsed'}');
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
ExpansionMode: UseExpansionModeproperty of theExpansionTileListwidget to control the expansion of the tiles. TheinitialExpandedIndexesproperty allows you to specify the indexes of the tiles that are initially expanded.ExpansionModethat enforces a single tile expansions at a time expects a single index in the arrayinitialExpandedIndexesi.e [ExpansionMode.atMostOne,ExpansionMode.exactlyOne], if multiple indexes are specified then only the first index at 0 is considered. If theinitialExpandedIndexesis not specified then the first tile is expanded by default.
NOTE: ExpansionMode that allows at lease one tile to be always expanded i.e [
ExpansionMode.atLeastOne,ExpansionMode.exactlyOne] disables theExpansionTilewidget to enforce this rule.
/// Use ExpansionMode property
/// length of `initialExpandedIndexes` for enforces at least one tile always expanded [`ExpansionMode.atLeastOne`, `ExpansionMode.exactlyOne`] should be 1 or 0.
var expansionTileList = ExpansionTileList(
initialExpandedIndexes: [0, 1], // defaults to [] if not specified
expansionMode: ExpansionMode.any, // defaults to ExpansionMode.any if not specified
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
// Use named constructor
var expansionTileList = ExpansionTileList(
expansionMode: ExpansionMode.atMostOne,
initialExpandedIndexes: [0], // defaults to [] if not specified
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
var expansionTileList = ExpansionTileList(
expansionMode: ExpansionMode.atLeastOne,
initialExpandedIndexes: [1],
// defaults to [0] if not specified and cannot be resolved by first initialExpandedIndex of children
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
var expansionTileList = ExpansionTileList(
expansionMode: ExpansionMode.exactlyOne,
initialExpandedIndexes: [0], // defaults to [0] if not specified
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
ExpansionTileList.singlenamed constructor: Use theExpansionTileList.singlenamed constructor to create a list of tiles with either theExpansionMode.atMostOneorExpansionMode.exactlyOneexpansion mode.
var expansionTileList = ExpansionTileList.single(
initialExpandedIndex: 0,
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
// Use ExpansionMode.atMostOne named constructor
- Using
ExpansionTileItem: Use theExpansionTileItemwidget to customize the trailing widget of the tiles.
var expansionTileList = ExpansionTileList(
children: <ExpansionTile>[
ExpansionTileItem(
title: Text('Tile 1'),
trailing: Icon(Icons.arrow_drop_down),
children: <Widget>[Text('Child 1')],
),
ExpansionTileItem(
title: Text('Tile 2'),
trailing: Icon(Icons.arrow_drop_down),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
ExpansionTileItemwithtrailingAnimation: Use theExpansionTileItemwidget with thetrailingAnimationproperty to customize the trailing widget of the tiles.
var expansionTileList = ExpansionTileList(
children: <ExpansionTile>[
ExpansionTileItem(
title: Text('Tile 1'),
trailing: Icon(Icons.arrow_drop_down),
trailingAnimation: Tween<double>(begin: 0, end: 0.5),
children: <Widget>[Text('Child 1')],
),
ExpansionTileItem(
title: Text('Tile 2'),
trailing: Icon(Icons.arrow_drop_down),
trailingAnimation: Tween<double>(begin: 0, end: 0.5),
children: <Widget>[Text('Child 2')],
),
],
);
- Using
ExpansionTileItemwithtrailingAnimationBuilder: Use theExpansionTileItemwidget with thetrailingAnimationBuilderproperty to customize the trailing widget of the tiles.
var expansionTileList = ExpansionTileList(
children: <ExpansionTile>[
ExpansionTileItem(
title: Text('Tile 1'),
trailing: Icon(Icons.arrow_drop_down),
trailingAnimationBuilder: (context, index, value, child) {
return Transform.rotate(
angle: value * pi,
child: child,
);
},
children: <Widget>[Text('Child 1')],
),
ExpansionTileItem(
title: Text('Tile 2'),
trailing: Icon(Icons.arrow_drop_down),
trailingAnimationBuilder: (context, index, value, child) {
return Transform.rotate(
angle: value * pi,
child: child,
);
},
children: <Widget>[Text('Child 2')],
),
],
);
How initialExpandedIndexes with ExpansionMode works #
ExpansionMode.atMostOne- considers
initialExpandedIndexesfirst valid index. - considers first
ExpansionTilechild widget withinitiallyExpandedtrue. - collapses all tiles.
- considers
ExpansionMode.exactlyOne- considers
initialExpandedIndexesfirst valid index. - considers first
ExpansionTilechild widget withinitiallyExpandedtrue. - considers first
ExpansionTilechild widget at index0.
- considers
ExpansionMode.atLeastOne- considers
initialExpandedIndexesall indexes if not empty. - considers all
ExpansionTilechildren widget withinitiallyExpandedtrue. - considers first
ExpansionTilechild widget at index0.
- considers
ExpansionMode.any- considers
initialExpandedIndexesall indexes if not empty. - considers all
ExpansionTilechildren widget withinitiallyExpandedtrue. - collapses all tiles.
- considers
How tileGapSize and separatorBuilder layout works #
tileGapSizeis the size of the gap between the tiles in the list.separatorBuilderis the builder for the separator between the tiles in the list. Note:tileGapSizeis always rendered before theseparatorBuilderif both are specified.- Layout as follows:
[ExpansionTile 1]
[Gap]
[Divider]
[ExpansionTile 2]
[Gap]
[Divider]
[ExpansionTile 3]
Properties #
| Property | Description | Default Value |
|---|---|---|
key |
The widget key. | null |
children |
The list of ExpansionTile widgets that are managed by this widget. | required |
onExpansionChanged |
Called whenever a tile is expanded or collapsed. | null |
tileGapSize |
The size of the gap between the tiles in the list. | 0.0 |
separatorBuilder |
The builder for the separator between the tiles in the list. | null |
tileBuilder |
A builder that can be used to customize the appearance of the tiles. | null |
controller |
A controller that can be used to programmatically control the expansion of the tiles. | null |
trailing |
The widget that is displayed at the end of each tile header. Can be overridden by trailing property of ExpansionList |
null |
trailingAnimation |
The animation for the trailing widget of the tiles. No effect of trailing property of ExpansionList if specified |
null |
enableTrailingAnimation |
Enable or disable the trailing animation. | true |
initialExpandedIndexes |
The indexes of the tiles that are initially expanded. | const <int>[] |
expansionMode |
The expansion mode of the ExpansionTileList. |
ExpansionMode.any |
Testing #
All testcase are available for the package.
- expansion_tile_extension_test.dart
- expansion_tile_list_test.dart
- expansion_tile_item_test.dart To run the tests, use the following command:
flutter test
Troubleshooting #
- If you encounter any issues while using the package, please check the GitHub issues page to see if the issue has already been reported.
- If you are unable to find a solution, please create a new issue with a detailed description of the problem, including the steps to reproduce it.
- If you have any questions or need help with the package, please feel free to reach out to the package maintainer.
- If you would like to contribute to the package, please refer to the Contributing section for more information.
- If you have any feedback or suggestions for the package, please share them with the package maintainer.
Known Issues #
- State Management issues with ExpansionTile children: Set maintainState to
truefor theExpansionTilechildren to maintain the state of the children when the parentExpansionTileListis rebuilt. - Expansion state issues: The expansion state of the
ExpansionTilemay not be maintained when the parentExpansionTileListis rebuilt due to the change of the widget tree. To maintain the expansion state, use a GlobalKey. - ExpansionTileList
tileBuilderissues: ThetileBuilderproperty may not work as expected when theExpansionTileis rebuilt due changes in the widget tree at runtime. To resolve this use a GlobalKey on the ExpansionTileList. - ExpansionTileController
controllerissues: Thecontrollerproperty may not work as expected when theExpansionTileis rebuilt due. To resolve this use a GlobalKey or ExpansionTileItemController to ensure.
Failed assertion: line 607 pos 12: 'widget.controller?._state == null': is not true.
These issues are due to the Flutter framework limitations and not the package. We have ensured that the package works as expected with the Flutter framework and made sure to take a safe decision to mitigate this issues. This means no issues should be encountered when using the package as intended.
Contributing #
Contributions are welcome! If you find a bug or want a feature, please fill an issue. If you want to contribute code, please submit a pull request. We welcome contributions from everyone. Before you start:
- Fork the repository to your own GitHub account.
- Clone the project to your machine.
- Create a branch locally with a descriptive name.
- Commit changes to the branch.
- Push changes to your fork.
- Create a new pull request in GitHub and link the issue you are fixing.
Visitors #
License #
This project is licensed under the BSD-style license. See the LICENSE file for details.