diff --git a/packages/animations/lib/src/open_container.dart b/packages/animations/lib/src/open_container.dart index 2454b3aeb5..f9ba91ad41 100644 --- a/packages/animations/lib/src/open_container.dart +++ b/packages/animations/lib/src/open_container.dart @@ -620,16 +620,10 @@ class _OpenContainerRoute extends ModalRoute { _currentAnimationStatus = status; switch (status) { case AnimationStatus.dismissed: - if (hideableKey?.currentState != null) { - hideableKey.currentState - ..placeholderSize = null - ..isVisible = true; - } + _toggleHideable(hide: false); break; case AnimationStatus.completed: - hideableKey.currentState - ..placeholderSize = null - ..isVisible = false; + _toggleHideable(hide: true); break; case AnimationStatus.forward: case AnimationStatus.reverse: @@ -649,6 +643,25 @@ class _OpenContainerRoute extends ModalRoute { return super.didPop(result); } + @override + void dispose() { + if (hideableKey?.currentState?.isVisible == false) { + // This route may be disposed without dismissing its animation if it is + // removed by the navigator. + SchedulerBinding.instance + .addPostFrameCallback((Duration d) => _toggleHideable(hide: false)); + } + super.dispose(); + } + + void _toggleHideable({bool hide}) { + if (hideableKey?.currentState != null) { + hideableKey.currentState + ..placeholderSize = null + ..isVisible = !hide; + } + } + void _takeMeasurements({ BuildContext navigatorContext, bool delayForSourceRoute = false, diff --git a/packages/animations/test/open_container_test.dart b/packages/animations/test/open_container_test.dart index 2628fbef9f..e276f45794 100644 --- a/packages/animations/test/open_container_test.dart +++ b/packages/animations/test/open_container_test.dart @@ -1733,6 +1733,47 @@ void main() { expect(modalRoute.settings, routeSettings); }, ); + + // Regression test for https://github.com/flutter/flutter/issues/72238. + testWidgets( + 'OpenContainer\'s source widget is visible in closed container route if ' + 'open container route is pushed from not using the OpenContainer itself', + (WidgetTester tester) async { + final Widget openContainer = OpenContainer( + closedBuilder: (BuildContext context, VoidCallback action) { + return GestureDetector( + onTap: action, + child: const Text('Closed'), + ); + }, + openBuilder: (BuildContext context, VoidCallback action) { + return GestureDetector( + onTap: action, + child: const Text('Open'), + ); + }, + ); + await tester.pumpWidget(_boilerplate(child: openContainer)); + expect(_getOpacity(tester, 'Closed'), 1.0); + + // Open the container + await tester.tap(find.text('Closed')); + await tester.pumpAndSettle(); + + final Element container = tester.element( + find.byType(OpenContainer, skipOffstage: false), + ); + // Replace the open container route. + Navigator.pushReplacement(container, + MaterialPageRoute(builder: (_) => const Placeholder())); + await tester.pumpAndSettle(); + // Go back to the main page and verify the closed builder is showed. + Navigator.pop(container); + await tester.pumpAndSettle(); + + expect(_getOpacity(tester, 'Closed'), 1.0); + }, + ); } Color _getScrimColor(WidgetTester tester) {