ExpansionTile class
A single-line ListTile with an expansion arrow icon that expands or collapses the tile to reveal or hide the children.
This widget is typically used with ListView to create an "expand / collapse" list entry. When used with scrolling widgets like ListView, a unique PageStorageKey must be specified as the key, to enable the ExpansionTile to save and restore its expanded state when it is scrolled in and out of view.
This class overrides the ListTileThemeData.iconColor and ListTileThemeData.textColor theme properties for its ListTile. These colors animate between values when the tile is expanded and collapsed: between iconColor, collapsedIconColor and between textColor and collapsedTextColor.
The expansion arrow icon is shown on the right by default in left-to-right languages (i.e. the trailing edge). This can be changed using controlAffinity. This maps to the leading and trailing properties of ExpansionTile.
This example demonstrates how the ExpansionTile icon's location and appearance can be customized.
To see it in action, copy and run this code snippet on DartPad.
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [ExpansionTile].
void main() => runApp(const ExpansionTileApp());
class ExpansionTileApp extends StatelessWidget {
const ExpansionTileApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ExpansionTile Sample')),
body: const ExpansionTileExample(),
),
);
}
}
class ExpansionTileExample extends StatefulWidget {
const ExpansionTileExample({super.key});
@override
State<ExpansionTileExample> createState() => _ExpansionTileExampleState();
}
class _ExpansionTileExampleState extends State<ExpansionTileExample> {
bool _customTileExpanded = false;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
const ExpansionTile(
title: Text('ExpansionTile 1'),
subtitle: Text('Trailing expansion arrow icon'),
children: <Widget>[ListTile(title: Text('This is tile number 1'))],
),
ExpansionTile(
title: const Text('ExpansionTile 2'),
subtitle: const Text('Custom expansion arrow icon'),
trailing: Icon(
_customTileExpanded
? Icons.arrow_drop_down_circle
: Icons.arrow_drop_down,
),
children: const <Widget>[
ListTile(title: Text('This is tile number 2')),
],
onExpansionChanged: (bool expanded) {
setState(() {
_customTileExpanded = expanded;
});
},
),
const ExpansionTile(
title: Text('ExpansionTile 3'),
subtitle: Text('Leading expansion arrow icon'),
controlAffinity: .leading,
children: <Widget>[ListTile(title: Text('This is tile number 3'))],
),
],
);
}
}
This example demonstrates how an ExpansibleController can be used to programmatically expand or collapse an ExpansionTile.
To see it in action, copy and run this code snippet on DartPad.
import 'package:material_ui/material_ui.dart';
/// Flutter code sample for [ExpansionTile] and [ExpansibleController].
void main() {
runApp(const ExpansionTileControllerApp());
}
class ExpansionTileControllerApp extends StatefulWidget {
const ExpansionTileControllerApp({super.key});
@override
State<ExpansionTileControllerApp> createState() =>
_ExpansionTileControllerAppState();
}
class _ExpansionTileControllerAppState
extends State<ExpansionTileControllerApp> {
final ExpansibleController controller = ExpansibleController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('ExpansionTileController Sample')),
body: Column(
children: <Widget>[
// A controller has been provided to the ExpansionTile because it's
// going to be accessed from a component that is not within the
// tile's BuildContext.
ExpansionTile(
controller: controller,
title: const Text('ExpansionTile with explicit controller.'),
children: <Widget>[
Container(
alignment: .center,
padding: const .all(24),
child: const Text('ExpansionTile Contents'),
),
],
),
const SizedBox(height: 8),
ElevatedButton(
child: const Text('Expand/Collapse the Tile Above'),
onPressed: () {
if (controller.isExpanded) {
controller.collapse();
} else {
controller.expand();
}
},
),
const SizedBox(height: 48),
// A controller has not been provided to the ExpansionTile because
// the automatically created one can be retrieved via the tile's BuildContext.
ExpansionTile(
title: const Text('ExpansionTile with implicit controller.'),
children: <Widget>[
Builder(
builder: (BuildContext context) {
return Container(
padding: const .all(24),
alignment: .center,
child: ElevatedButton(
child: const Text('Collapse This Tile'),
onPressed: () {
return ExpansibleController.of(context).collapse();
},
),
);
},
),
],
),
],
),
),
);
}
}
Accessibility
The accessibility behavior of ExpansionTile is platform adaptive, based on the device's actual platform rather than the theme's platform setting. This ensures that assistive technologies like VoiceOver on iOS and macOS receive the correct platform-specific semantics hints, even when the app's theme is configured to mimic a different platform's appearance.
See also:
- ListTile, useful for creating expansion tile children when the expansion tile represents a sublist.
- The "Expand and collapse" section of material.io/components/lists#types
- Inheritance
-
- Object
- DiagnosticableTree
- Widget
- StatefulWidget
- ExpansionTile
Constructors
-
ExpansionTile({Key? key, Widget? leading, required Widget title, Widget? subtitle, ValueChanged<
bool> ? onExpansionChanged, List<Widget> children = const <Widget>[], Widget? trailing, bool showTrailingIcon = true, bool initiallyExpanded = false, bool maintainState = false, EdgeInsetsGeometry? tilePadding, CrossAxisAlignment? expandedCrossAxisAlignment, AlignmentGeometry? expandedAlignment, EdgeInsetsGeometry? childrenPadding, Color? backgroundColor, Color? collapsedBackgroundColor, Color? textColor, Color? collapsedTextColor, Color? iconColor, Color? collapsedIconColor, ShapeBorder? shape, ShapeBorder? collapsedShape, Clip? clipBehavior, ListTileControlAffinity? controlAffinity, ExpansibleController? controller, bool? dense, Color? splashColor, VisualDensity? visualDensity, double? minTileHeight, bool? enableFeedback = true, bool enabled = true, AnimationStyle? expansionAnimationStyle, bool internalAddSemanticForOnTap = false, WidgetStatesController? statesController}) -
Creates a single-line ListTile with an expansion arrow icon that expands or collapses
the tile to reveal or hide the
children. TheinitiallyExpandedproperty must be non-null.const
Properties
- backgroundColor → Color?
-
The color to display behind the sublist when expanded.
final
-
children
→ List<
Widget> -
The widgets that are displayed when the tile expands.
final
- childrenPadding → EdgeInsetsGeometry?
-
Specifies padding for children.
final
- clipBehavior → Clip?
-
The content will be clipped (or not) according to this option.
final
- collapsedBackgroundColor → Color?
-
When not null, defines the background color of tile when the sublist is collapsed.
final
- collapsedIconColor → Color?
-
The icon color of tile's expansion arrow icon when the sublist is collapsed.
final
- collapsedShape → ShapeBorder?
-
The tile's border shape when the sublist is collapsed.
final
- collapsedTextColor → Color?
-
The color of the tile's titles when the sublist is collapsed.
final
- controlAffinity → ListTileControlAffinity?
-
Typically used to force the expansion arrow icon to the tile's leading or trailing edge.
final
- controller → ExpansibleController?
-
If provided, the controller can be used to expand and collapse tiles.
final
- dense → bool?
-
Whether this list tile is part of a vertically dense list.
final
- enabled → bool
-
Whether this expansion tile is interactive.
final
- enableFeedback → bool?
-
Whether detected gestures should provide acoustic and/or haptic feedback.
final
- expandedAlignment → AlignmentGeometry?
-
Specifies the alignment of children, which are arranged in a column when
the tile is expanded.
final
- expandedCrossAxisAlignment → CrossAxisAlignment?
-
Specifies the alignment of each child within children when the tile is expanded.
final
- expansionAnimationStyle → AnimationStyle?
-
Used to override the expansion animation curve and duration.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
- iconColor → Color?
-
The icon color of tile's expansion arrow icon when the sublist is expanded.
final
- initiallyExpanded → bool
-
Specifies if the list tile is initially expanded (true) or collapsed (false).
final
- internalAddSemanticForOnTap → bool
-
Whether to add button:true to the semantics if onTap is provided.
This is a temporary flag to help changing the behavior of ListTile onTap semantics.
final
- key → Key?
-
Controls how one widget replaces another widget in the tree.
finalinherited
- leading → Widget?
-
A widget to display before the title.
final
- maintainState → bool
-
Specifies whether the state of the children is maintained when the tile expands and collapses.
final
- minTileHeight → double?
-
The minimum height allocated for the ListTile widget.
final
-
onExpansionChanged
→ ValueChanged<
bool> ? -
Called when the tile expands or collapses.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- shape → ShapeBorder?
-
The tile's border shape when the sublist is expanded.
final
- showTrailingIcon → bool
-
Specifies if the ExpansionTile should build a default trailing icon if trailing is null.
final
- splashColor → Color?
-
The splash color of the ink response when the tile is tapped.
final
- statesController → WidgetStatesController?
-
The controller that notifies when the widget's WidgetStates change.
final
- subtitle → Widget?
-
Additional content displayed below the title.
final
- textColor → Color?
-
The color of the tile's titles when the sublist is expanded.
final
- tilePadding → EdgeInsetsGeometry?
-
Specifies padding for the ListTile.
final
- title → Widget
-
The primary content of the list item.
final
- trailing → Widget?
-
A widget to display after the title.
final
- visualDensity → VisualDensity?
-
Defines how compact the expansion tile's layout will be.
final
Methods
-
createElement(
) → StatefulElement -
Creates a StatefulElement to manage this widget's location in the tree.
inherited
-
createState(
) → State< ExpansionTile> -
Creates the mutable state for this widget at a given location in the tree.
override
-
debugDescribeChildren(
) → List< DiagnosticsNode> -
Returns a list of DiagnosticsNode objects describing this node's
children.
inherited
-
debugFillProperties(
DiagnosticPropertiesBuilder properties) → void -
Add additional properties associated with the node.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toDiagnosticsNode(
{String? name, DiagnosticsTreeStyle? style}) → DiagnosticsNode -
Returns a debug representation of the object that is used by debugging
tools and by DiagnosticsNode.toStringDeep.
inherited
-
toString(
{DiagnosticLevel minLevel = DiagnosticLevel.info}) → String -
A string representation of this object.
inherited
-
toStringDeep(
{String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug, int wrapWidth = 65}) → String -
Returns a string representation of this node and its descendants.
inherited
-
toStringShallow(
{String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) → String -
Returns a one-line detailed description of the object.
inherited
-
toStringShort(
) → String -
A short, textual description of this widget.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited