Skip to content

Commit adc5f26

Browse files
authored
Re-land ScaffoldMessenger (flutter#65416)
1 parent c067557 commit adc5f26

File tree

11 files changed

+820
-302
lines changed

11 files changed

+820
-302
lines changed

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

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'floating_action_button.dart';
1717
import 'icons.dart';
1818
import 'material_localizations.dart';
1919
import 'page.dart';
20+
import 'scaffold.dart';
2021
import 'theme.dart';
2122

2223
/// [MaterialApp] uses this [TextStyle] as its [DefaultTextStyle] to encourage
@@ -168,6 +169,7 @@ class MaterialApp extends StatefulWidget {
168169
const MaterialApp({
169170
Key key,
170171
this.navigatorKey,
172+
this.scaffoldMessengerKey,
171173
this.home,
172174
this.routes = const <String, WidgetBuilder>{},
173175
this.initialRoute,
@@ -215,6 +217,7 @@ class MaterialApp extends StatefulWidget {
215217
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
216218
const MaterialApp.router({
217219
Key key,
220+
this.scaffoldMessengerKey,
218221
this.routeInformationProvider,
219222
@required this.routeInformationParser,
220223
@required this.routerDelegate,
@@ -263,6 +266,14 @@ class MaterialApp extends StatefulWidget {
263266
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
264267
final GlobalKey<NavigatorState> navigatorKey;
265268

269+
/// A key to use when building the [ScaffoldMessenger].
270+
///
271+
/// If a [scaffoldMessengerKey] is specified, the [ScaffoldMessenger] can be
272+
/// directly manipulated without first obtaining it from a [BuildContext] via
273+
/// [ScaffoldMessenger.of]: from the [scaffoldMessengerKey], use the
274+
/// [GlobalKey.currentState] getter.
275+
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey;
276+
266277
/// {@macro flutter.widgets.widgetsApp.home}
267278
final Widget home;
268279

@@ -722,27 +733,30 @@ class _MaterialAppState extends State<MaterialApp> {
722733
}
723734
theme ??= widget.theme ?? ThemeData.light();
724735

725-
return AnimatedTheme(
726-
data: theme,
727-
isMaterialAppTheme: true,
728-
child: widget.builder != null
729-
? Builder(
730-
builder: (BuildContext context) {
731-
// Why are we surrounding a builder with a builder?
732-
//
733-
// The widget.builder may contain code that invokes
734-
// Theme.of(), which should return the theme we selected
735-
// above in AnimatedTheme. However, if we invoke
736-
// widget.builder() directly as the child of AnimatedTheme
737-
// then there is no Context separating them, and the
738-
// widget.builder() will not find the theme. Therefore, we
739-
// surround widget.builder with yet another builder so that
740-
// a context separates them and Theme.of() correctly
741-
// resolves to the theme we passed to AnimatedTheme.
742-
return widget.builder(context, child);
743-
},
744-
)
745-
: child,
736+
return ScaffoldMessenger(
737+
key: widget.scaffoldMessengerKey,
738+
child: AnimatedTheme(
739+
data: theme,
740+
isMaterialAppTheme: true,
741+
child: widget.builder != null
742+
? Builder(
743+
builder: (BuildContext context) {
744+
// Why are we surrounding a builder with a builder?
745+
//
746+
// The widget.builder may contain code that invokes
747+
// Theme.of(), which should return the theme we selected
748+
// above in AnimatedTheme. However, if we invoke
749+
// widget.builder() directly as the child of AnimatedTheme
750+
// then there is no Context separating them, and the
751+
// widget.builder() will not find the theme. Therefore, we
752+
// surround widget.builder with yet another builder so that
753+
// a context separates them and Theme.of() correctly
754+
// resolves to the theme we passed to AnimatedTheme.
755+
return widget.builder(context, child);
756+
},
757+
)
758+
: child,
759+
)
746760
);
747761
}
748762

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
137137
/// icon: const Icon(Icons.add_alert),
138138
/// tooltip: 'Show Snackbar',
139139
/// onPressed: () {
140-
/// scaffoldKey.currentState.showSnackBar(snackBar);
140+
/// ScaffoldMessenger.of(context).showSnackBar(snackBar);
141141
/// },
142142
/// ),
143143
/// IconButton(

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:flutter/widgets.dart';
99

1010
import 'material.dart';
1111
import 'material_localizations.dart';
12-
import 'scaffold.dart' show Scaffold;
12+
import 'scaffold.dart' show Scaffold, ScaffoldMessenger;
1313

1414
/// Asserts that the given context has a [Material] ancestor.
1515
///
@@ -125,3 +125,34 @@ bool debugCheckHasScaffold(BuildContext context) {
125125
}());
126126
return true;
127127
}
128+
129+
/// Asserts that the given context has a [ScaffoldMessenger] ancestor.
130+
///
131+
/// Used by various widgets to make sure that they are only used in an
132+
/// appropriate context.
133+
///
134+
/// To invoke this function, use the following pattern, typically in the
135+
/// relevant Widget's build method:
136+
///
137+
/// ```dart
138+
/// assert(debugCheckHasScaffoldMessenger(context));
139+
/// ```
140+
///
141+
/// Does nothing if asserts are disabled. Always returns true.
142+
bool debugCheckHasScaffoldMessenger(BuildContext context) {
143+
assert(() {
144+
if (context.widget is! ScaffoldMessenger && context.findAncestorWidgetOfExactType<ScaffoldMessenger>() == null) {
145+
throw FlutterError.fromParts(<DiagnosticsNode>[
146+
ErrorSummary('No ScaffoldMessenger widget found.'),
147+
ErrorDescription('${context.widget.runtimeType} widgets require a ScaffoldMessenger widget ancestor.'),
148+
...context.describeMissingAncestor(expectedAncestorType: ScaffoldMessenger),
149+
ErrorHint(
150+
'Typically, the ScaffoldMessenger widget is introduced by the MaterialApp '
151+
'at the top of your application widget tree.'
152+
)
153+
]);
154+
}
155+
return true;
156+
}());
157+
return true;
158+
}

0 commit comments

Comments
 (0)