diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index f9c3893c0c90..4b4ab9ea93a1 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -2029,7 +2029,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto bool get isEndDrawerOpen => _endDrawerOpened.value; void _drawerOpenedCallback(bool isOpened) { - if (_drawerOpened.value != isOpened) { + if (_drawerOpened.value != isOpened && _drawerKey.currentState != null) { setState(() { _drawerOpened.value = isOpened; }); @@ -2038,7 +2038,7 @@ class ScaffoldState extends State with TickerProviderStateMixin, Resto } void _endDrawerOpenedCallback(bool isOpened) { - if (_endDrawerOpened.value != isOpened) { + if (_endDrawerOpened.value != isOpened && _endDrawerKey.currentState != null) { setState(() { _endDrawerOpened.value = isOpened; }); diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart index 0fe90959bc7b..4c9aa6db94ec 100644 --- a/packages/flutter/test/material/drawer_test.dart +++ b/packages/flutter/test/material/drawer_test.dart @@ -422,6 +422,87 @@ void main() { expect(find.text('Drawer'), findsNothing); }); + testWidgets('Disposing drawer does not crash if drawer is open and framework is locked', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/34978 + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + tester.binding.window.physicalSizeTestValue = const Size(1800.0, 2400.0); + + await tester.pumpWidget( + MaterialApp( + home: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + switch (orientation) { + case Orientation.portrait: + return Scaffold( + drawer: const Text('drawer'), + body: Container(), + ); + case Orientation.landscape: + return Scaffold( + appBar: AppBar(), + body: Container(), + ); + } + }, + ), + ), + ); + + expect(find.text('drawer'), findsNothing); + + // Using a global key is a workaround for this issue. + final ScaffoldState portraitScaffoldState = tester.firstState(find.byType(Scaffold)); + portraitScaffoldState.openDrawer(); + await tester.pumpAndSettle(); + expect(find.text('drawer'), findsOneWidget); + + // Change the orientation and cause the drawer controller to be disposed + // while the framework is locked. + tester.binding.window.physicalSizeTestValue = const Size(2400.0, 1800.0); + await tester.pumpAndSettle(); + expect(find.byType(BackButton), findsNothing); + }); + + testWidgets('Disposing endDrawer does not crash if endDrawer is open and framework is locked', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/34978 + addTearDown(tester.binding.window.clearPhysicalSizeTestValue); + tester.binding.window.physicalSizeTestValue = const Size(1800.0, 2400.0); + + await tester.pumpWidget( + MaterialApp( + home: OrientationBuilder( + builder: (BuildContext context, Orientation orientation) { + switch (orientation) { + case Orientation.portrait: + return Scaffold( + endDrawer: const Text('endDrawer'), + body: Container(), + ); + case Orientation.landscape: + return Scaffold( + appBar: AppBar(), + body: Container(), + ); + } + }, + ), + ), + ); + + expect(find.text('endDrawer'), findsNothing); + + // Using a global key is a workaround for this issue. + final ScaffoldState portraitScaffoldState = tester.firstState(find.byType(Scaffold)); + portraitScaffoldState.openEndDrawer(); + await tester.pumpAndSettle(); + expect(find.text('endDrawer'), findsOneWidget); + + // Change the orientation and cause the drawer controller to be disposed + // while the framework is locked. + tester.binding.window.physicalSizeTestValue = const Size(2400.0, 1800.0); + await tester.pumpAndSettle(); + expect(find.byType(BackButton), findsNothing); + }); testWidgets('ScaffoldState close end drawer', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey();