Unverified Commit eb9bac64 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

ScaffoldMessenger only shows to root nested Scaffold (#74093)

parent 4bdea117
......@@ -68,6 +68,12 @@ enum _ScaffoldSlot {
/// [BuildContext] via [ScaffoldMessenger.of] and use the
/// [ScaffoldMessengerState.showSnackBar] function.
///
/// When the [ScaffoldMessenger] has nested [Scaffold] descendants, the
/// ScaffoldMessenger will only present a [SnackBar] to the root Scaffold of
/// the subtree of Scaffolds. In order to show SnackBars in the inner, nested
/// Scaffolds, set a new scope for your SnackBars by instantiating a new
/// ScaffoldMessenger in between the levels of nesting.
///
/// {@tool dartpad --template=stateless_widget_scaffold_center}
///
/// Here is an example of showing a [SnackBar] when the user presses a button.
......@@ -377,10 +383,18 @@ class ScaffoldMessengerState extends State<ScaffoldMessenger> with TickerProvide
void _updateScaffolds() {
for (final ScaffoldState scaffold in _scaffolds) {
scaffold._updateSnackBar();
if (_isRoot(scaffold))
scaffold._updateSnackBar();
}
}
// Nested Scaffolds are handled by the ScaffoldMessenger by only presenting a
// SnackBar in the root Scaffold of the nested set.
bool _isRoot(ScaffoldState scaffold) {
final ScaffoldState? parent = scaffold.context.findAncestorStateOfType<ScaffoldState>();
return parent == null || !_scaffolds.contains(parent);
}
/// Removes the current [SnackBar] (if any) immediately from registered
/// [Scaffold]s.
///
......
......@@ -2291,4 +2291,36 @@ void main() {
await expectLater(find.byType(MaterialApp), matchesGoldenFile('snack_bar.goldenTest.workWithBottomSheet.png'));
});
testWidgets('ScaffoldMessenger presents SnackBars to only the root Scaffold when Scaffolds are nested.', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: const Scaffold(),
floatingActionButton: FloatingActionButton(onPressed: () {}),
),
));
final ScaffoldMessengerState scaffoldMessengerState = tester.state<ScaffoldMessengerState>(
find.byType(ScaffoldMessenger),
);
scaffoldMessengerState.showSnackBar(SnackBar(
content: const Text('ScaffoldMessenger'),
duration: const Duration(seconds: 2),
action: SnackBarAction(label: 'ACTION', onPressed: () {}),
behavior: SnackBarBehavior.floating,
));
await tester.pumpAndSettle();
expect(find.byType(SnackBar), findsOneWidget);
// The FloatingActionButton helps us identify which Scaffold has the
// SnackBar here. Since the outer Scaffold contains a FAB, the SnackBar
// should be above it. If the inner Scaffold had the SnackBar, it would be
// overlapping the FAB.
await expectLater(
find.byType(MaterialApp),
matchesGoldenFile('snack_bar.scaffold.nested.png'),
);
final Offset snackBarTopRight = tester.getTopRight(find.byType(SnackBar));
expect(snackBarTopRight.dy, 465.0);
});
}
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