mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +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.trailing,
|
||||
this.initiallyExpanded = false,
|
||||
this.maintainState = false,
|
||||
this.tilePadding,
|
||||
this.expandedCrossAxisAlignment,
|
||||
this.expandedAlignment,
|
||||
}) : assert(initiallyExpanded != null),
|
||||
assert(maintainState != null),
|
||||
assert(
|
||||
expandedCrossAxisAlignment != CrossAxisAlignment.baseline,
|
||||
'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).
|
||||
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].
|
||||
///
|
||||
/// Analogous to [ListTile.contentPadding], this property defines the insets for
|
||||
|
@ -253,13 +262,23 @@ class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProvider
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final bool closed = !_isExpanded && _controller.isDismissed;
|
||||
final bool shouldRemoveChildren = closed && !widget.maintainState;
|
||||
|
||||
final Widget result = Offstage(
|
||||
child: TickerMode(
|
||||
child: Column(
|
||||
crossAxisAlignment: widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
|
||||
children: widget.children,
|
||||
),
|
||||
enabled: !closed,
|
||||
),
|
||||
offstage: closed
|
||||
);
|
||||
|
||||
return AnimatedBuilder(
|
||||
animation: _controller.view,
|
||||
builder: _buildChildren,
|
||||
child: closed ? null : Column(
|
||||
crossAxisAlignment: widget.expandedCrossAxisAlignment ?? CrossAxisAlignment.center,
|
||||
children: widget.children,
|
||||
),
|
||||
child: shouldRemoveChildren ? null : result,
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -230,6 +230,46 @@ void main() {
|
|||
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 {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Material(
|
||||
|
|
Loading…
Reference in a new issue