mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Add option for ExpansionTile to maintain the state of its children when collapsed (#57172)
This commit is contained in:
parent
859f2f9bd4
commit
2b2bbfa69f
@ -41,10 +41,12 @@ class ExpansionTile extends StatefulWidget {
|
|||||||
this.children = const <Widget>[],
|
this.children = const <Widget>[],
|
||||||
this.trailing,
|
this.trailing,
|
||||||
this.initiallyExpanded = false,
|
this.initiallyExpanded = false,
|
||||||
|
this.maintainState = false,
|
||||||
this.tilePadding,
|
this.tilePadding,
|
||||||
this.expandedCrossAxisAlignment,
|
this.expandedCrossAxisAlignment,
|
||||||
this.expandedAlignment,
|
this.expandedAlignment,
|
||||||
}) : assert(initiallyExpanded != null),
|
}) : assert(initiallyExpanded != null),
|
||||||
|
assert(maintainState != null),
|
||||||
assert(
|
assert(
|
||||||
expandedCrossAxisAlignment != CrossAxisAlignment.baseline,
|
expandedCrossAxisAlignment != CrossAxisAlignment.baseline,
|
||||||
'CrossAxisAlignment.baseline is not supported since the expanded children '
|
'CrossAxisAlignment.baseline is not supported since the expanded children '
|
||||||
@ -88,6 +90,13 @@ class ExpansionTile extends StatefulWidget {
|
|||||||
/// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
|
/// Specifies if the list tile is initially expanded (true) or collapsed (false, the default).
|
||||||
final bool initiallyExpanded;
|
final bool initiallyExpanded;
|
||||||
|
|
||||||
|
/// Specifies whether the state of the children is maintained when the tile expands and collapses.
|
||||||
|
///
|
||||||
|
/// When true, the children are kept in the tree while the tile is collapsed.
|
||||||
|
/// When false (default), the children are removed from the tree when the tile is
|
||||||
|
/// collapsed and recreated upon expansion.
|
||||||
|
final bool maintainState;
|
||||||
|
|
||||||
/// Specifies padding for the [ListTile].
|
/// Specifies padding for the [ListTile].
|
||||||
///
|
///
|
||||||
/// Analogous to [ListTile.contentPadding], this property defines the insets for
|
/// Analogous to [ListTile.contentPadding], this property defines the insets for
|
||||||
@ -253,13 +262,23 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final bool closed = !_isExpanded && _controller.isDismissed;
|
final bool closed = !_isExpanded && _controller.isDismissed;
|
||||||
return AnimatedBuilder(
|
final bool shouldRemoveChildren = closed && !widget.maintainState;
|
||||||
animation: _controller.view,
|
|
||||||
builder: _buildChildren,
|
final Widget result = Offstage(
|
||||||
child: closed ? null : Column(
|
child: TickerMode(
|
||||||
|
child: Column(
|
||||||
crossAxisAlignment: widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
|
crossAxisAlignment: widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
|
||||||
children: widget.children,
|
children: widget.children,
|
||||||
),
|
),
|
||||||
|
enabled: !closed,
|
||||||
|
),
|
||||||
|
offstage: closed
|
||||||
|
);
|
||||||
|
|
||||||
|
return AnimatedBuilder(
|
||||||
|
animation: _controller.view,
|
||||||
|
builder: _buildChildren,
|
||||||
|
child: shouldRemoveChildren ? null : result,
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -230,6 +230,46 @@ void main() {
|
|||||||
expect(find.text('Subtitle'), findsOneWidget);
|
expect(find.text('Subtitle'), findsOneWidget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ExpansionTile maintainState', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
MaterialApp(
|
||||||
|
theme: ThemeData(
|
||||||
|
platform: TargetPlatform.iOS,
|
||||||
|
dividerColor: _dividerColor,
|
||||||
|
),
|
||||||
|
home: Material(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: const <Widget>[
|
||||||
|
ExpansionTile(
|
||||||
|
title: Text('Tile 1'),
|
||||||
|
initiallyExpanded: false,
|
||||||
|
maintainState: true,
|
||||||
|
children: <Widget>[
|
||||||
|
Text('Maintaining State'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ExpansionTile(
|
||||||
|
title: Text('Title 2'),
|
||||||
|
initiallyExpanded: false,
|
||||||
|
maintainState: false,
|
||||||
|
children: <Widget>[
|
||||||
|
Text('Discarding State'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
// This text should be offstage while ExpansionTile collapsed
|
||||||
|
expect(find.text('Maintaining State', skipOffstage: false), findsOneWidget);
|
||||||
|
expect(find.text('Maintaining State'), findsNothing);
|
||||||
|
// This text shouldn't be there while ExpansionTile collapsed
|
||||||
|
expect(find.text('Discarding State'), findsNothing);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('ExpansionTile padding test', (WidgetTester tester) async {
|
testWidgets('ExpansionTile padding test', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(const MaterialApp(
|
await tester.pumpWidget(const MaterialApp(
|
||||||
home: Material(
|
home: Material(
|
||||||
|
Loading…
Reference in New Issue
Block a user