v2.0.0expansion_tile_list
Ein anpassbarer Satz von Erweiterungstiles mit vielseitigen Optionen für Styling, Animationen und Steuerung des Erweiterungsverhaltens, während wesentliche Funktionen vereinfacht werden, um die Nutzung zu erleichtern.
Eine Erweiterungstile-Liste dient als Container für Erweiterungstile-Widgets
{"sdk":"flutter"}{"sdk":"flutter"}^3.0.2Englischer Projektschnappschuss. Aktuelle Inhalte auf GitHub.
The ExpansionTileList serves as a container for the ExpansionTile widget, enabling the creation of a list of
ExpansionTile items. It offers additional features that allow you to customize the appearance of the tiles and control
their expansion programmatically.
pub package pub points pub points popularity Flutter Widget
The expansion_tile_list package offers a highly customizable list of expansion_tile items for Flutter applications.
It enables developers to create expandable tile lists with extensive options for appearance, animations, and control
over the expansion behaviour. The package includes features such as a global trailing widget, trailing animation, and
various expansion modes to accommodate different use cases.
Basic Usage Trailing Controller Expansion Mode Reorderable Drag handle
ExpansionTile widgets.ExpansionTileItem widget instead of ExpansionTileExpansionTileListController.List FeaturesAll the features affects all the tiles in the ExpansionTileList.
itemGapSize allows you to specify the size of the gap between each tile in the ExpansionTileList.trailing allows you to specify the trailing widget for all tiles, can be overridden byExpansionTile
trailing property.trailingAnimation allows you to specify a custom animation for the trailing widget.enableTrailingAnimation allows you to enable or disable the trailing animation.itemBuilder allows the customization of the creation and appearance of the tiles in the ExpansionTileList.separatorBuilder allows the customization of the creation and appearance of the separators between the tiles in the
ExpansionTileList.initialExpandedIndexes allows you to specify the indexes of the tiles that are initially expanded.controller allows you to programmatically control the expansion of the tiles.onExpansionChanged allows you to listen to the expansion changes of the tiles.ExpansionMode allows you to specify the expansion mode for the
ExpansionTileList.
ExpansionMode.atMostOne allows you to expand at most one tile at a time. (i.e. zero or one )ExpansionMode.atLeastOne ensures that at least one tile is always expanded (i.e. one or more )ExpansionMode.exactlyOne allows you to expand exactly one tile at a time. (i.e. one )ExpansionMode.any allows you to expand any number of tiles. (i.e. zero or more )separatorAlignment allows you to specify the alignment of the separator against the space itemGapSize between
the tiles in the ExpansionTileListheader allows you to specify a widget displayed at the beginning of the list.footer allows you to specify a widget displayed at the end of the list.ExpansionTileList.reorderable enable the list to be reorderable
by dragging the items.canReorder onReorder allows you to
specify a callback to control the behavior of the list item reordering.dragHandleBuilder allows you to customize the appearance of the
drag handle for the reorderable list.Item FeaturesBy 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.
trailing allows you to specify the trailing widget for the tile.trailingAnimation allows you to specify a custom animation for the trailing widget.enableTrailingAnimation allows you to enable or disable the trailing animation.To use this package, add expansion_tile_list as
a dependency in your pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
expansion_tile_list: ^2.0.0
Import the package:
import 'package:expansion_tile_list/expansion_tile_list.dart';
Here are some simple examples of how to use the ExpansionTileList: check out
the demo
ExpansionTile widgets using the ExpansionTileList widget.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(
itemGapSize: 10.0,
children: <Widget>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[
Text('Child 1'),
],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[
Text('Child 2'),
],
),
],
),
),
);
}
}
trailing and trailingAnimation: use the trailing and trailingAnimation properties 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')],
),
],
);
itemBuilder: This property allows you to customize the appearance of the items in the list.
var expansionTileList = ExpansionTileList(
itemBuilder: (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')],
),
],
);
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')],
),
],
);
**See Also: ** How itemGapSize and separatorBuilder layout works
itemGapSize: This property allows you to specify the size of the gap between each tile in the list.
var expansionTileList = ExpansionTileList(
itemGapSize: 10.0, // defaults to 0.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')],
),
],
);
separatorBuilder: This property allows you to customize the appearance of the separators between the
ExpansionTile items in the list.
var expansionTileList =
ExpansionTileList(
separatorAlignment: Alignment.topCenter, // defaults to Alignment.bottomCenter if not specified
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')],
),
],
);
separatorAlignment: This property allows you to specify the alignment of the separator against the space
itemGapSize between the tiles in the list.
var expansionTileList = ExpansionTileList(
separatorAlignment: Alignment.topCenter, // defaults to Alignment.bottomCenter 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')],
),
],
);
header and footer: Use the header and footer properties to add widgets before and after the list items.var expansionTileList = ExpansionTileList(
header: Padding(
padding: EdgeInsets.all(16.0),
child: Text('List Header', style: TextStyle(fontWeight: FontWeight.bold)),
),
footer: Padding(
padding: EdgeInsets.all(16.0),
child: Text('List Footer'),
),
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
**See Also: ** How ExpansionTileList current position and initial position works
controller: This property allows you to programmatically control the expansion of the ExpansionTile items.
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 tile
controller.collapse(0);
/// Toggle the first
controller.toggle(0);
/// Expand all
controller.expandAll();
/// Collapse all tiles
controller.collapseAll();
///
controller.toggleAll();
///
controller.initialPosition(currentPosition);
///
controller.currentPosition(initialPosition);
}
**See Also: ** How initialExpandedIndexes with ExpansionMode works
ExpansionMode: Use ExpansionMode property of the ExpansionTileList widget to control the expansion of the
tiles. The initialExpandedIndexes property allows you to specify the indexes of the tiles that are initially
expanded. ExpansionMode that enforces a single tile expansions at a time expects a single index in the array
initialExpandedIndexes i.e. ExpansionMode.atMostOne and ExpansionMode.exactlyOne, if multiple indexes are
specified then only the first index at 0 is considered. If the initialExpandedIndexes is not specified then the
first tile is expanded by default./// 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')],
),
],
);
ExpansionTileItem is an alternative to the default ExpansionTile, it intend to provide more fine grained control over the default where necessary.
ExpansionTileItem: Use the ExpansionTileItem widget 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')],
),
],
);
ExpansionTileItem with trailingAnimation: Use the ExpansionTileItem widget with
the trailingAnimation property 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')],
),
],
);
ExpansionTileItem with trailingAnimationBuilder: Use the ExpansionTileItem widget with the
trailingAnimationBuilder property 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')],
),
],
);
ExapnsionTileList.reorderable: Use the ExpansionTileList.reorderable constructor to enable the list to be
reorderable by dragging the items.
var expansionTileList = ExpansionTileList.reorderable(
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
reorderable : Use the callbacks to listen to the reordering of the items in the list.// Use the canReorder and onReorder callback
var expansionTileList = ExpansionTileList.reorderable(
canReorder: (oldIndex, newIndex) { // allow reordering only if the new index is greater than the old index (drag down)
return newIndex > oldIndex;
},
onReorder: (oldIndex, newIndex) {
print('Reordered from $oldIndex to $newIndex');
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
// Use the onReorderStart and onReorderEnd callback
var expansionTileList = ExpansionTileList.reorderable(
onReorderStart: (index) { // called when the reordering starts at the index
print('Reorder started at $index');
},
onReorderEnd: (index) { // called when the reordering ends at the index
print('Reorder ended at $index');
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
useDelayedDrag: Use the useDelayedDrag property to enable delayed drag (long press) to start reordering the
items in
the list.
var expansionTileList = ExpansionTileList.reorderable(
useDelayedDrag: true, // enable delayed drag (long press) to start reordering
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
proxyDecorator: Use the proxyDecorator property to customize the appearance of the proxy item that is
displayed while reordering the items in the list.
var expansionTileList = ExpansionTileList.reorderable(
proxyDecorator: (Widget child, int index,
Animation<double> animation) { // customize the appearance of the proxy item during reordering (dragging)
return Material(
elevation: 4.0,
child: SizeTransition(
sizeFactor: animation,
child: child,
),
);
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
]
,
);
NOTE: The drag handle is a widget used to reorder the items in the list by dragging.
enableDefaultDragHandles : Use the enableDefaultDragHandles property to enable the default drag handles for
the reorderable list and useDelayedDrag for a long press to trigger reordering. The default drag handles makes the
whole ExpansionTile item draggable. This can be set to false when a custom drag handle is required.
// Use default drag handles with delayed drag
var expansionTileList = ExpansionTileList.reorderable(
enableDefaultDragHandles: true, // defaults to true if not specified
useDelayedDrag: true, // enable delayed drag (long press) to start reordering
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
dragHandlePlacement property to specify the placement of the drag handle for the
reorderable list.
var expansionTileList = ExpansionTileList.reorderable(
dragHandlePlacement: DragHandlePlacement.trailing, // defaults to DragHandlePlacement.none 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')],
),
],
);
dragHandleAlignment property to specify the horizontal alignment of the drag
handle relative to its placement for the reorderable list.
var expansionTileList = ExpansionTileList.reorderable(
dragHandleAlignment: HorizontalAlignment.centerRight, // defaults to HorizontalAlignment.centerLeft 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')],
),
],
);
dragHandleBuilder property to customize the appearance of the drag handle for the
reorderable list based on the DragHandlePlacement value. NOTE: DragHandlePlacement.none does not call the
dragHandleBuilder. The dragHandleBuilder can be used as a custom drag handle when the enableDefaultDragHandles is set
to false.
// decorate the drag handle based on DragHandlePlacement (child is the drag handle placement widget (leading , trailing or title))
// DragHandlePlacement.none does not call the dragHandleBuilder
var expansionTileList = ExpansionTileList.reorderable(
dragHandlerPlacement: DragHandlePlacement.leading,
// important for dragHandleBuilder to know the placement of the drag handle
dragHandleBuilder: (context, index, child) { // customize the appearance of the drag handle
return child == null ? const Icon(Icons.drag_handle) : Row(
mainAxisSize: MainAxisSize.min, //give it a min size to avoid overflow
children: <Widget>[
const Icon(Icons.drag_handle),
!child,
],
);
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
// use as a custom drag handle (only a specific widget is used as the handle)
// disable the default drag handles (enableDefaultDragHandles = false) and use either the ReorderableDragStartListener or ReorderableDelayedDragStartListener to create a custom drag handle for the reorderable list.
var expansionTileList = ExpansionTileList.reorderable(
enableDefaultDragHandles: false,
// disable the default drag handles
dragHandlerPlacement: DragHandlePlacement.leading,
// important for dragHandleBuilder to know the placement of the drag handle
dragHandleBuilder: (context, index, child) { // customize the appearance of the drag handle
final dragHandle = ReorderableDragStartListener(
key: PageStorageKey(index),
index: index,
child: const Icon(Icons.drag_handle),
);
return child == null ? dragHandle : Row(
mainAxisSize: MainAxisSize.min, //give it a min size to avoid overflow
children: <Widget>[
dragHandle,
!child,
],
);
},
children: <ExpansionTile>[
ExpansionTile(
title: Text('Tile 1'),
children: <Widget>[Text('Child 1')],
),
ExpansionTile(
title: Text('Tile 2'),
children: <Widget>[Text('Child 2')],
),
],
);
ReorderableDragStartListener or
ReorderableDelayedDragStartListener to create a custom drag handle for the reorderable list.
NOTE:
dragHandleBuilderis a simpler way to create a custom drag handle for the reorderable list.
final ValueNotifier<(int, int)> _reorderNotifier = ValueNotifier((-1, -1)); // remember to dispose the ValueNotifier
final ExpansionTileListController _controller = ExpansionTileListController();
var expansionTileList = ExpansionTileList.reorderable(
enableDefaultDragHandles: false, // defaults to true if not specified
controller: _controller, // controller to programmatically control tiles and access the position of the tiles
onReorder: (oldIndex, newIndex) {
_reorderNotifier.value = (oldIndex, newIndex); // notify the custom drag handle of the reorder
},
children: <ExpansionTile>[
...List.generate(10, (index) {
return ExpansionTile(
leading: _buildCustomDragHandle(index),
title: Text('Tile $index'),
children: <Widget>[Text('Child $index')],
);
}),
],
);
Widget _buildCustomDragHandle(int itemIndex) {
return ValueListenableBuilder<(int, int)>(
valueListenable: _reorderNotifier,
builder: (context, (int, int) value, child) {
return ReorderableDragStartListener(
key: PageStorageKey(itemIndex),
index: _controller.currentPosition(itemIndex),
child: const Icon(Icons.drag_handle),
);
});
}
// for large items in a list, to improve performance a custom drag handle can be created as below
// Note: _reorderNotifier should be reset to (-1, -1) in the didUpdateWidget lifecycle method when setState is called to rebuild the list.
@Override
void didUpdateWidget() {
_reorderNotifier.value = (-1, -1);
}
Widget _buildCustomDragHandle(int itemIndex) {
Widget dragHandle(int index) {
return ReorderableDragStartListener(
key: PageStorageKey(index),
index: index,
child: const Icon(Icons.drag_handle),
);
}
Widget? currentDragHandle;
return ValueListenableBuilder<(int, int)>(
valueListenable: _reorderNotifier,
child: currentDragHandle,
builder: (context, (int, int) value, child) {
var minIndex = min(value.$1, value.$2);
var maxIndex = max(value.$1, value.$2);
var index = _controller.currentPosition(itemIndex);
if (minIndex < 0 || (index >= minIndex &&
index <= maxIndex)) { //only update when reorder index is within the range of oldIndex and newIndex or is -1
currentDragHandle =
(index == itemIndex ? child : null) ?? dragHandle(index);
}
return currentDragHandle ?? dragHandle(index);
},
);
}
By default the whole widget is draggable for a reorderable expansion list.
To create use a widget as a drag handle, use dragHandleBuilder to customize the appearance of the drag handle and use
dragHandlePlacement and dragHandleAlignment to specify the placement and alignment of the drag handle respectively.
For a custom drag handle, disable the default drag handles by setting enableDefaultDragHandles to false.
enableDefaultDragHandles is used to enable the default drag handles for the reorderable list. Only set false if you
intend to build custom drag handles.useDelayedDrag is used to enable the delayed drag (long press) to start reordering.dragHandlePlacement is used to specify the placement of the drag handle. This works for both the default drag
handles
and the custom drag handles (i.e enableDefaultDragHandles is false).dragHandleAlignment is used to specify the alignment of the drag handle in relation to the space between the tiles.dragHandleBuilder is used only when dragHandlePlacement has a value other than DragHandlePlacement.none to
customize the appearance of the drag handle based on the DragHandlePlacement widget.ExpansionMode.atMostOne
initialExpandedIndexes first valid index.ExpansionTile child widget withinitiallyExpanded true.ExpansionMode.exactlyOne
initialExpandedIndexes first valid index.ExpansionTile child widget withinitiallyExpanded true.ExpansionTile child widget at index 0.ExpansionMode.atLeastOne
initialExpandedIndexes all indexes if not empty.ExpansionTile children widget withinitiallyExpanded true.ExpansionTile child widget at index 0.ExpansionMode.any
initialExpandedIndexes all indexes if not empty.ExpansionTile children widget withinitiallyExpanded true.itemGapSize is the size of the gap between the tiles in the list.separatorBuilder is the builder which returns a separator widget rendered between the ExpansionTile items in the
list.separatorAlignment is the alignment of the separator widget in relation to the space itemGapSize between items.NOTE: The
separatorAlignmentcan be used to specify the alignment of the separator against the space
Alignment.topLeft Alignment.topCenter Alignment.topRight
[ExpansionTile 1] [ExpansionTile 1] [ExpansionTile 1]
[ Gap ] [ Gap ] [ Gap ]
[Divider] [Divider] [Divider]
[ExpansionTile 2] [ExpansionTile 2] [ExpansionTile 2]
[ Gap ] [ Gap ] [ Gap ]
[Divider] [Divider] [Divider]
[ExpansionTile 3] [ExpansionTile 3] [ExpansionTile 3]
Alignment.centerLeft Alignment.center Alignment.centerRight
[ExpansionTile 1] [ExpansionTile 1] [ExpansionTile 1]
[ Gap/2 ] [ Gap/2 ] [ Gap/2 ]
[Divider] [Divider] [Divider]
[ Gap/2 ] [ Gap/2 ] [ Gap/2 ]
[ExpansionTile 2] [ExpansionTile 2] [ExpansionTile 2]
[ Gap/2 ] [ Gap/2 ] [ Gap/2 ]
[Divider] [Divider] [Divider]
[ Gap/2 ] [ Gap/2 ] [ Gap/2 ]
[ExpansionTile 3] [ExpansionTile 3] [ExpansionTile 3]
Alignment.bottomLeft Alignment.bottomCenter Alignment.bottonRight
[ExpansionTile 1] [ExpansionTile 1] [ExpansionTile 1]
[Divider] [Divider] [Divider]
[ Gap ] [ Gap ] [ Gap ]
[ExpansionTile 2] [ExpansionTile 2] [ExpansionTile 2]
[Divider] [Divider] [Divider]
[ Gap ] [ Gap ] [ Gap ]
[ExpansionTile 3] [ExpansionTile 3] [ExpansionTile 3]
ExpansionTileList item initial position is the index of the ExpansionTile in the children list of the
ExpansionTileList on creation and before reordering.ExpansionTileList, an item current position will always be the same as the initial position.ExpansionTileList, the current position is the index of the ExpansionTile in the items of the
ExpansionTileList after reordering.current position.
var controller = ExpansionTileListController();
_() {
// before reordering
controller.initialPosition(0); // returns 0
// after reordering
controller.initialPosition(2); // returns 0
}
var controller = ExpansionTileListController();
_() {
// before reordering
controller.currentPosition(0); // returns 0
// after reordering
controller.currentPosition(0); // returns 2
}
| 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 |
itemGapSize |
The size of the gap between the tiles in the list. (renamed to itemGapSize from next major release) | 0.0 |
separatorBuilder |
The builder for the separator between the tiles in the list. | null |
itemBuilder |
A builder that can be used to customize the appearance of the tiles. (renamed to itemBuilder from next major release) | 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 ExpansionTile |
null |
trailingAnimation |
The animation for the trailing widget of the tiles. Can be overridden by trailingAnimation property of ExpansionTile |
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 |
separatorAlignment |
The alignment of the separator widget in relation to the space itemGapSize between items |
Alignment.bottomCenter |
header |
The widget displayed at the beginning of the items in the list. | null |
footer |
The widget displayed at the end of the items in the list. | null |
| Property | Description | Default Value |
|---|---|---|
scrollDirection |
The direction in which the list scrolls | Axis.vertical |
reverse |
Whether the list scrolls in reverse | false |
scrollController |
An object that can be used to control the position to which this scroll view is scrolled. | null |
primary |
Whether this is the primary scroll view associated with the parent PrimaryScrollController. |
true |
physics |
How the scroll view should respond to user input. | AlwaysScrollableScrollPhysics() |
shrinkWrap |
Whether the extent of the scroll view in the scroll direction should be determined by the contents being viewed. | false |
padding |
The amount of space by which to inset the list contents. | EdgeInsets.zero |
restorationId |
An identifier that will be used to save the scroll position in the restoration data. | null |
keyboardDismissBehavior |
How the scroll view should respond to keyboard events. | ScrollViewKeyboardDismissBehavior.manual |
dragStartBehavior |
Determines the way that drag start behavior is handled. | DragStartBehavior.start |
clipBehavior |
Determines how to clip the content of the scroll view. | Clip.hardEdge |
| Property | Description | Default Value |
|---|---|---|
reorderable |
Readonly bool property indicating if the ExpansionTileList can be reordered |
false |
canReorder |
A callback that returns whether the item at the given index can be reordered. | null |
onReorder |
A callback invoked when an item has been reordered. | null |
onReorderStart |
A callback invoked when the user starts reordering an item | null |
onReorderEnd |
A callback invoked when the user stops reordering an item | null |
proxyDecorator |
A builder that can be used to customize the appearance of the proxy item that is displayed while reordering. | null |
enableDefaultDragHandles |
A bool property indicating if the default drag handles should be used for the reorderable list. | true |
useDelayedDrag |
A bool property indicating if delayed (long press) drag start should trigger item reordering. | false |
dragHandlePlacement |
The placement of the drag handle in the ExpansionTile. | DragHandlePlacement.none |
dragHandleAlignment |
The alignment of the drag handle in the ExpansionTile. | HorizontalAlignment.centerLeft |
dragHandleBuilder |
A builder that can be used to customize the appearance of the drag handle for the reorderable list. | null |
anchor |
Determines the relative position of the zero scroll offset within the viewport. (values: 0.0 to 1.0) | 0.0 |
autoScrollerVelocityScalar |
Enables you to adjust the speed of the auto-scroll behavior during drag-and-drop operations | 50 |
| Property | Description | Default Value |
|---|---|---|
controller |
Programmatically control the expansion using ExpansionTileController or ExpansionTileItemController. |
null |
trailing |
The widget that is displayed at the end of each tile header. | null |
trailingAnimation |
The animation for the trailing widget of the tiles. | null |
enableTrailingAnimation |
Enable or disable the trailing animation. | true |
All testcase are available for the source.
flutter test
true for the
ExpansionTile children to maintain the state of the children when the parent ExpansionTileList is rebuilt.ExpansionTile may not be maintained when the parent of
ExpansionTileList is rebuilt due to the change of the widget tree. To maintain the expansion state, use a GlobalKey
on the ExpansionTile.itemBuilder issues: If the itemBuilder modifies the widget tree during a rebuild, it may disrupt
the maintenance of the expansion state of the ExpansionTile. To address this, use a GlobalKey on the
ExpansionTile.controller issues: The controller property may not function as expected when the
ExpansionTile modifies the widget tree during a rebuild. To resolve this, use a GlobalKey or delegate
the management of the controller to ExpansionTileList by using ExpansionTileItemController type as a controller. Failed assertion: line 607 pos 12: 'widget.controller?._state == null': is not true.
ExpansionTileController controller methods may throw an assertion error when the widget is not yet mounted or
initialized, mostly due to item not visible in scroll viewport. To resolve this, always check for init state
controller.isInitialized before calling the controller methods.
Using a ListView or ScrollView within the ExpansionTile children may cause layout issues. To resolve this, use a
Column or Container with a fixed height as parent to the ListView and use a PageStorageKey(index) on the
ListView.
The following _TypeError was thrown building ListView(scrollDirection: vertical, dependencies: [MediaQuery]): type 'bool' is not a subtype of type 'double?' in type cast
These issues are due to the ExpansionTile widget 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 these issues.
This means no issues should be encountered when using the package as intended.
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:
Visitor Count
This project is licensed under the BSD-style license. See the License file for details.
Leave a thumbs up 👍 if you like the package.