Unverified Commit 5047690b authored by Devin's avatar Devin Committed by GitHub

ExpansionPanel isExpanded callback parameter (Ticket 74114) (#128082)

Fixes https://github.com/flutter/flutter/issues/74114

This PR addresses the issue detailed here: https://github.com/flutter/flutter/issues/74114 . The boolean isExpanded returned by the expansion panel callback now reflects the state of the panel that the user is seeing. If it's expanded on screen then the callback returns true. When you close the panel the callback returns false. When another panel is open and you open a different one, the callback executes twice. It returns isExpanded == false for the panel you are closing and true for the panel that is being opened.
I had to change the code in a couple existing tests because some tests are using the old behavior of the callback. This PR addresses feedback listed in closed PR -> https://github.com/flutter/flutter/pull/127876 . The reasone the original PR is closed is that I was having some struggles with git. A couple of the commits in this PR are just reverts of commits I meant not to happen.
Pre-launch Checklist

    [ X] I read the [Contributor Guide](https://github.com/flutter/flutter/wiki/Tree-hygiene#overview) and followed the process outlined there for submitting PRs.
    [ X] I read the [Tree Hygiene](https://github.com/flutter/flutter/wiki/Tree-hygiene) wiki page, which explains my responsibilities.
    [ X] I read and followed the [Flutter Style Guide](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo), including [Features we expect every widget to implement](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement).
    [ X] I signed the [CLA](https://cla.developers.google.com/).
    [ X] I listed at least one issue that this PR fixes in the description above.
    I updated/added relevant documentation (doc comments with ///).
    [ X] I added new tests to check the change I am making, or this PR is [test-exempt](https://github.com/flutter/flutter/wiki/Tree-hygiene#tests).
    [ X] All existing and new tests are passing.
parent 38406ff8
......@@ -345,7 +345,7 @@ class _ExpansionPanelsDemoState extends State<ExpansionPanelsDemo> {
child: ExpansionPanelList(
expansionCallback: (int index, bool isExpanded) {
setState(() {
_demoItems[index].isExpanded = !isExpanded;
_demoItems[index].isExpanded = isExpanded;
});
},
children: _demoItems.map<ExpansionPanel>((DemoItem<dynamic> item) {
......
......@@ -313,9 +313,7 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
return widget.children[index].isExpanded;
}
void _handlePressed(bool isExpanded, int index) {
widget.expansionCallback?.call(index, isExpanded);
void _handlePressed(bool isExpanded, int index) {
if (widget._allowOnlyOnePanelOpen) {
final ExpansionPanelRadio pressedChild = widget.children[index] as ExpansionPanelRadio;
......@@ -334,6 +332,8 @@ class _ExpansionPanelListState extends State<ExpansionPanelList> {
_currentOpenPanel = isExpanded ? null : pressedChild;
});
}
// !isExpanded is passed because, when _handlePressed, the state of the panel to expand is not yet expanded.
widget.expansionCallback?.call(index, !isExpanded);
}
ExpansionPanelRadio? searchPanelByValue(List<ExpansionPanelRadio> panels, Object? value) {
......
......@@ -144,7 +144,7 @@ void main() {
expect(find.byType(ExpandIcon), findsOneWidget);
await tester.tap(find.byType(ExpandIcon));
expect(capturedIndex, 0);
expect(capturedIsExpanded, isFalse);
expect(capturedIsExpanded, isTrue);
box = tester.renderObject(find.byType(ExpansionPanelList));
expect(box.size.height, equals(oldHeight));
......@@ -556,7 +556,7 @@ void main() {
// Callback is invoked once with appropriate arguments
expect(callbackHistory.length, equals(1));
expect(callbackHistory.last['index'], equals(1));
expect(callbackHistory.last['isExpanded'], equals(false));
expect(callbackHistory.last['isExpanded'], equals(true));
// Close the same panel
await tester.tap(find.byType(ExpandIcon).at(1));
......@@ -565,7 +565,7 @@ void main() {
// Callback is invoked once with appropriate arguments
expect(callbackHistory.length, equals(2));
expect(callbackHistory.last['index'], equals(1));
expect(callbackHistory.last['isExpanded'], equals(true));
expect(callbackHistory.last['isExpanded'], equals(false));
});
testWidgets('Radio mode calls expansionCallback twice if other panel open prior', (WidgetTester tester) async {
......@@ -630,7 +630,7 @@ void main() {
expect(callbackHistory.length, equals(1));
callbackResults = callbackHistory[callbackHistory.length - 1];
expect(callbackResults['index'], equals(1));
expect(callbackResults['isExpanded'], equals(false));
expect(callbackResults['isExpanded'], equals(true));
// Close a different panel
await tester.tap(find.byType(ExpandIcon).at(2));
......@@ -639,13 +639,108 @@ void main() {
// Callback is invoked the first time with correct arguments
expect(callbackHistory.length, equals(3));
callbackResults = callbackHistory[callbackHistory.length - 2];
expect(callbackResults['index'], equals(2));
expect(callbackResults['index'], equals(1));
expect(callbackResults['isExpanded'], equals(false));
// Callback is invoked the second time with correct arguments
callbackResults = callbackHistory[callbackHistory.length - 1];
expect(callbackResults['index'], equals(1));
expect(callbackResults['isExpanded'], equals(false));
expect(callbackResults['index'], equals(2));
expect(callbackResults['isExpanded'], equals(true));
});
testWidgets('ExpansionPanelList.radio callback displays true or false based on the visibility of a list item', (WidgetTester tester) async {
late int lastExpanded;
bool topElementExpanded = false;
bool bottomElementExpanded = false;
final List<ExpansionPanel> demoItemsRadio = <ExpansionPanelRadio>[
// topElement
ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return Text(isExpanded ? 'B' : 'A');
},
body: const SizedBox(height: 100.0),
value: 0,
),
// bottomElement
ExpansionPanelRadio(
headerBuilder: (BuildContext context, bool isExpanded) {
return Text(isExpanded ? 'D' : 'C');
},
body: const SizedBox(height: 100.0),
value: 1,
),
];
final ExpansionPanelList expansionListRadio = ExpansionPanelList.radio(
children: demoItemsRadio,
expansionCallback: (int index, bool isExpanded)
{
lastExpanded = index;
if (index == 0)
{
topElementExpanded = isExpanded;
bottomElementExpanded = false;
}
else
{
topElementExpanded = false;
bottomElementExpanded = isExpanded;
}
}
);
await tester.pumpWidget(
MaterialApp(
home: SingleChildScrollView(
child: expansionListRadio,
),
),
);
// Initializes with all panels closed.
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
await tester.tap(find.byType(ExpandIcon).at(0));
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
// Now the first panel is open.
expect(find.text('A'), findsNothing);
expect(find.text('B'), findsOneWidget);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
expect(lastExpanded,0);
expect(topElementExpanded,true);
await tester.tap(find.byType(ExpandIcon).at(1));
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
// Open the other panel and ensure the first is now closed.
expect(lastExpanded,1);
expect(bottomElementExpanded,true);
expect(topElementExpanded,false);
expect(find.text('D'), findsOneWidget);
expect(find.text('A'), findsOneWidget);
await tester.tap(find.byType(ExpandIcon).at(1));
await tester.pump(const Duration(milliseconds: 200));
await tester.pumpAndSettle();
// Close the item that was expanded should now be false.
expect(lastExpanded,1);
expect(bottomElementExpanded,false);
// All panels should be closed.
expect(find.text('A'), findsOneWidget);
expect(find.text('B'), findsNothing);
expect(find.text('C'), findsOneWidget);
expect(find.text('D'), findsNothing);
});
testWidgets(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment