Skip to content

Commit da3b2a2

Browse files
Fix Scaffold setState during locked framework due to open drawer (#107173)
1 parent 2f0a252 commit da3b2a2

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

packages/flutter/lib/src/material/scaffold.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,7 +2029,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
20292029
bool get isEndDrawerOpen => _endDrawerOpened.value;
20302030

20312031
void _drawerOpenedCallback(bool isOpened) {
2032-
if (_drawerOpened.value != isOpened) {
2032+
if (_drawerOpened.value != isOpened && _drawerKey.currentState != null) {
20332033
setState(() {
20342034
_drawerOpened.value = isOpened;
20352035
});
@@ -2038,7 +2038,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
20382038
}
20392039

20402040
void _endDrawerOpenedCallback(bool isOpened) {
2041-
if (_endDrawerOpened.value != isOpened) {
2041+
if (_endDrawerOpened.value != isOpened && _endDrawerKey.currentState != null) {
20422042
setState(() {
20432043
_endDrawerOpened.value = isOpened;
20442044
});

packages/flutter/test/material/drawer_test.dart

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,87 @@ void main() {
422422
expect(find.text('Drawer'), findsNothing);
423423
});
424424

425+
testWidgets('Disposing drawer does not crash if drawer is open and framework is locked', (WidgetTester tester) async {
426+
// Regression test for https://github.com/flutter/flutter/issues/34978
427+
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
428+
tester.binding.window.physicalSizeTestValue = const Size(1800.0, 2400.0);
429+
430+
await tester.pumpWidget(
431+
MaterialApp(
432+
home: OrientationBuilder(
433+
builder: (BuildContext context, Orientation orientation) {
434+
switch (orientation) {
435+
case Orientation.portrait:
436+
return Scaffold(
437+
drawer: const Text('drawer'),
438+
body: Container(),
439+
);
440+
case Orientation.landscape:
441+
return Scaffold(
442+
appBar: AppBar(),
443+
body: Container(),
444+
);
445+
}
446+
},
447+
),
448+
),
449+
);
450+
451+
expect(find.text('drawer'), findsNothing);
452+
453+
// Using a global key is a workaround for this issue.
454+
final ScaffoldState portraitScaffoldState = tester.firstState(find.byType(Scaffold));
455+
portraitScaffoldState.openDrawer();
456+
await tester.pumpAndSettle();
457+
expect(find.text('drawer'), findsOneWidget);
458+
459+
// Change the orientation and cause the drawer controller to be disposed
460+
// while the framework is locked.
461+
tester.binding.window.physicalSizeTestValue = const Size(2400.0, 1800.0);
462+
await tester.pumpAndSettle();
463+
expect(find.byType(BackButton), findsNothing);
464+
});
465+
466+
testWidgets('Disposing endDrawer does not crash if endDrawer is open and framework is locked', (WidgetTester tester) async {
467+
// Regression test for https://github.com/flutter/flutter/issues/34978
468+
addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
469+
tester.binding.window.physicalSizeTestValue = const Size(1800.0, 2400.0);
470+
471+
await tester.pumpWidget(
472+
MaterialApp(
473+
home: OrientationBuilder(
474+
builder: (BuildContext context, Orientation orientation) {
475+
switch (orientation) {
476+
case Orientation.portrait:
477+
return Scaffold(
478+
endDrawer: const Text('endDrawer'),
479+
body: Container(),
480+
);
481+
case Orientation.landscape:
482+
return Scaffold(
483+
appBar: AppBar(),
484+
body: Container(),
485+
);
486+
}
487+
},
488+
),
489+
),
490+
);
491+
492+
expect(find.text('endDrawer'), findsNothing);
493+
494+
// Using a global key is a workaround for this issue.
495+
final ScaffoldState portraitScaffoldState = tester.firstState(find.byType(Scaffold));
496+
portraitScaffoldState.openEndDrawer();
497+
await tester.pumpAndSettle();
498+
expect(find.text('endDrawer'), findsOneWidget);
499+
500+
// Change the orientation and cause the drawer controller to be disposed
501+
// while the framework is locked.
502+
tester.binding.window.physicalSizeTestValue = const Size(2400.0, 1800.0);
503+
await tester.pumpAndSettle();
504+
expect(find.byType(BackButton), findsNothing);
505+
});
425506

426507
testWidgets('ScaffoldState close end drawer', (WidgetTester tester) async {
427508
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();

0 commit comments

Comments
 (0)