Skip to content

Commit

Permalink
ScaffoldMessenger (flutter#64101)
Browse files Browse the repository at this point in the history
  • Loading branch information
Piinks authored Sep 3, 2020
1 parent b6e92cf commit 48f1a0a
Show file tree
Hide file tree
Showing 11 changed files with 818 additions and 302 deletions.
56 changes: 35 additions & 21 deletions packages/flutter/lib/src/material/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'floating_action_button.dart';
import 'icons.dart';
import 'material_localizations.dart';
import 'page.dart';
import 'scaffold.dart';
import 'theme.dart';

/// [MaterialApp] uses this [TextStyle] as its [DefaultTextStyle] to encourage
Expand Down Expand Up @@ -168,6 +169,7 @@ class MaterialApp extends StatefulWidget {
const MaterialApp({
Key key,
this.navigatorKey,
this.scaffoldMessengerKey,
this.home,
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
Expand Down Expand Up @@ -215,6 +217,7 @@ class MaterialApp extends StatefulWidget {
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
const MaterialApp.router({
Key key,
this.scaffoldMessengerKey,
this.routeInformationProvider,
@required this.routeInformationParser,
@required this.routerDelegate,
Expand Down Expand Up @@ -263,6 +266,14 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
final GlobalKey<NavigatorState> navigatorKey;

/// A key to use when building the [ScaffoldMessenger].
///
/// If a [scaffoldMessengerKey] is specified, the [ScaffoldMessenger] can be
/// directly manipulated without first obtaining it from a [BuildContext] via
/// [ScaffoldMessenger.of]: from the [scaffoldMessengerKey], use the
/// [GlobalKey.currentState] getter.
final GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey;

/// {@macro flutter.widgets.widgetsApp.home}
final Widget home;

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

return AnimatedTheme(
data: theme,
isMaterialAppTheme: true,
child: widget.builder != null
? Builder(
builder: (BuildContext context) {
// Why are we surrounding a builder with a builder?
//
// The widget.builder may contain code that invokes
// Theme.of(), which should return the theme we selected
// above in AnimatedTheme. However, if we invoke
// widget.builder() directly as the child of AnimatedTheme
// then there is no Context separating them, and the
// widget.builder() will not find the theme. Therefore, we
// surround widget.builder with yet another builder so that
// a context separates them and Theme.of() correctly
// resolves to the theme we passed to AnimatedTheme.
return widget.builder(context, child);
},
)
: child,
return ScaffoldMessenger(
key: widget.scaffoldMessengerKey,
child: AnimatedTheme(
data: theme,
isMaterialAppTheme: true,
child: widget.builder != null
? Builder(
builder: (BuildContext context) {
// Why are we surrounding a builder with a builder?
//
// The widget.builder may contain code that invokes
// Theme.of(), which should return the theme we selected
// above in AnimatedTheme. However, if we invoke
// widget.builder() directly as the child of AnimatedTheme
// then there is no Context separating them, and the
// widget.builder() will not find the theme. Therefore, we
// surround widget.builder with yet another builder so that
// a context separates them and Theme.of() correctly
// resolves to the theme we passed to AnimatedTheme.
return widget.builder(context, child);
},
)
: child,
)
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/flutter/lib/src/material/app_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class _ToolbarContainerLayout extends SingleChildLayoutDelegate {
/// icon: const Icon(Icons.add_alert),
/// tooltip: 'Show Snackbar',
/// onPressed: () {
/// scaffoldKey.currentState.showSnackBar(snackBar);
/// ScaffoldMessenger.of(context).showSnackBar(snackBar);
/// },
/// ),
/// IconButton(
Expand Down
33 changes: 32 additions & 1 deletion packages/flutter/lib/src/material/debug.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import 'package:flutter/widgets.dart';

import 'material.dart';
import 'material_localizations.dart';
import 'scaffold.dart' show Scaffold;
import 'scaffold.dart' show Scaffold, ScaffoldMessenger;

/// Asserts that the given context has a [Material] ancestor.
///
Expand Down Expand Up @@ -125,3 +125,34 @@ bool debugCheckHasScaffold(BuildContext context) {
}());
return true;
}

/// Asserts that the given context has a [ScaffoldMessenger] ancestor.
///
/// Used by various widgets to make sure that they are only used in an
/// appropriate context.
///
/// To invoke this function, use the following pattern, typically in the
/// relevant Widget's build method:
///
/// ```dart
/// assert(debugCheckHasScaffoldMessenger(context));
/// ```
///
/// Does nothing if asserts are disabled. Always returns true.
bool debugCheckHasScaffoldMessenger(BuildContext context) {
assert(() {
if (context.widget is! ScaffoldMessenger && context.findAncestorWidgetOfExactType<ScaffoldMessenger>() == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary('No ScaffoldMessenger widget found.'),
ErrorDescription('${context.widget.runtimeType} widgets require a ScaffoldMessenger widget ancestor.'),
...context.describeMissingAncestor(expectedAncestorType: ScaffoldMessenger),
ErrorHint(
'Typically, the ScaffoldMessenger widget is introduced by the MaterialApp '
'at the top of your application widget tree.'
)
]);
}
return true;
}());
return true;
}
Loading

0 comments on commit 48f1a0a

Please sign in to comment.