Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
64c845c5
Unverified
Commit
64c845c5
authored
Oct 05, 2020
by
Kate Lovett
Committed by
GitHub
Oct 05, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-land ScaffoldMessenger (#66504)
parent
7f2ca5e5
Changes
12
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
1568 additions
and
178 deletions
+1568
-178
app.dart
packages/flutter/lib/src/material/app.dart
+35
-21
app_bar.dart
packages/flutter/lib/src/material/app_bar.dart
+1
-1
debug.dart
packages/flutter/lib/src/material/debug.dart
+32
-1
scaffold.dart
packages/flutter/lib/src/material/scaffold.dart
+596
-38
snack_bar.dart
packages/flutter/lib/src/material/snack_bar.dart
+17
-15
animated_list.dart
packages/flutter/lib/src/widgets/animated_list.dart
+3
-1
framework.dart
packages/flutter/lib/src/widgets/framework.dart
+40
-21
debug_test.dart
packages/flutter/test/material/debug_test.dart
+81
-0
floating_action_button_location_test.dart
...r/test/material/floating_action_button_location_test.dart
+1
-1
scaffold_test.dart
packages/flutter/test/material/scaffold_test.dart
+111
-0
snack_bar_test.dart
packages/flutter/test/material/snack_bar_test.dart
+646
-74
snack_bar_theme_test.dart
packages/flutter/test/material/snack_bar_theme_test.dart
+5
-5
No files found.
packages/flutter/lib/src/material/app.dart
View file @
64c845c5
...
...
@@ -15,6 +15,7 @@ import 'floating_action_button.dart';
import
'icons.dart'
;
import
'material_localizations.dart'
;
import
'page.dart'
;
import
'scaffold.dart'
show
ScaffoldMessenger
,
ScaffoldMessengerState
;
import
'theme.dart'
;
/// [MaterialApp] uses this [TextStyle] as its [DefaultTextStyle] to encourage
...
...
@@ -166,6 +167,7 @@ class MaterialApp extends StatefulWidget {
const
MaterialApp
({
Key
?
key
,
this
.
navigatorKey
,
this
.
scaffoldMessengerKey
,
this
.
home
,
this
.
routes
=
const
<
String
,
WidgetBuilder
>{},
this
.
initialRoute
,
...
...
@@ -214,6 +216,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
,
...
...
@@ -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
;
...
...
@@ -724,27 +735,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
!,
)
);
}
...
...
packages/flutter/lib/src/material/app_bar.dart
View file @
64c845c5
...
...
@@ -135,7 +135,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(
...
...
packages/flutter/lib/src/material/debug.dart
View file @
64c845c5
...
...
@@ -7,7 +7,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.
///
...
...
@@ -123,3 +123,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
.
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
;
}
packages/flutter/lib/src/material/scaffold.dart
View file @
64c845c5
This diff is collapsed.
Click to expand it.
packages/flutter/lib/src/material/snack_bar.dart
View file @
64c845c5
...
...
@@ -32,7 +32,7 @@ const Curve _snackBarFadeOutCurve = Interval(0.72, 1.0, curve: Curves.fastOutSlo
/// Specify how a [SnackBar] was closed.
///
/// The [ScaffoldState.showSnackBar] function returns a
/// The [Scaffold
Messenger
State.showSnackBar] function returns a
/// [ScaffoldFeatureController]. The value of the controller's closed property
/// is a Future that resolves to a SnackBarClosedReason. Applications that need
/// to know how a snackbar was closed can use this value.
...
...
@@ -40,7 +40,7 @@ const Curve _snackBarFadeOutCurve = Interval(0.72, 1.0, curve: Curves.fastOutSlo
/// Example:
///
/// ```dart
/// Scaffold.of(context).showSnackBar(
/// Scaffold
Messenger
.of(context).showSnackBar(
/// SnackBar( ... )
/// ).closed.then((SnackBarClosedReason reason) {
/// ...
...
...
@@ -57,10 +57,10 @@ enum SnackBarClosedReason {
swipe
,
/// The snack bar was closed by the [ScaffoldFeatureController] close callback
/// or by calling [ScaffoldState.hideCurrentSnackBar] directly.
/// or by calling [Scaffold
Messenger
State.hideCurrentSnackBar] directly.
hide
,
/// The snack bar was closed by an call to [ScaffoldState.removeCurrentSnackBar].
/// The snack bar was closed by an call to [Scaffold
Messenger
State.removeCurrentSnackBar].
remove
,
/// The snack bar was closed because its timer expired.
...
...
@@ -150,8 +150,8 @@ class _SnackBarActionState extends State<SnackBarAction> {
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=zpO6n_oZWw0}
///
/// To display a snack bar, call `Scaffold
.of(context).showSnackBar()`, passing
/// an instance of [SnackBar] that describes the message.
/// To display a snack bar, call `Scaffold
Messenger.of(context).showSnackBar()`,
///
passing
an instance of [SnackBar] that describes the message.
///
/// To control how long the [SnackBar] remains visible, specify a [duration].
///
...
...
@@ -160,11 +160,11 @@ class _SnackBarActionState extends State<SnackBarAction> {
///
/// See also:
///
/// * [Scaffold
.of], to obtain the current [ScaffoldState], which manages the
/// display and animation of snack bars.
/// * [ScaffoldState.showSnackBar], which displays a [SnackBar].
/// * [Scaffold
State.removeCurrentSnackBar], which abruptly hides the currently
/// displayed snack bar, if any, and allows the next to be displayed.
/// * [Scaffold
Messenger.of], to obtain the current [ScaffoldMessengerState],
///
which manages the
display and animation of snack bars.
/// * [Scaffold
Messenger
State.showSnackBar], which displays a [SnackBar].
/// * [Scaffold
MessengerState.removeCurrentSnackBar], which abruptly hides the
///
currently
displayed snack bar, if any, and allows the next to be displayed.
/// * [SnackBarAction], which is used to specify an [action] button to show
/// on the snack bar.
/// * [SnackBarThemeData], to configure the default property values for
...
...
@@ -293,7 +293,7 @@ class SnackBar extends StatefulWidget {
///
/// See also:
///
/// * [ScaffoldState.removeCurrentSnackBar], which abruptly hides the
/// * [Scaffold
Messenger
State.removeCurrentSnackBar], which abruptly hides the
/// currently displayed snack bar, if any, and allows the next to be
/// displayed.
/// * <https://material.io/design/components/snackbars.html>
...
...
@@ -305,7 +305,7 @@ class SnackBar extends StatefulWidget {
/// Called the first time that the snackbar is visible within a [Scaffold].
final
VoidCallback
?
onVisible
;
// API for Scaffold.showSnackBar():
// API for Scaffold
MessengerState
.showSnackBar():
/// Creates an animation controller useful for driving a snack bar's entrance and exit animation.
static
AnimationController
createAnimationController
({
required
TickerProvider
vsync
})
{
...
...
@@ -342,7 +342,6 @@ class SnackBar extends StatefulWidget {
State
<
SnackBar
>
createState
()
=>
_SnackBarState
();
}
class
_SnackBarState
extends
State
<
SnackBar
>
{
bool
_wasVisible
=
false
;
...
...
@@ -560,6 +559,9 @@ class _SnackBarState extends State<SnackBar> {
);
}
return
ClipRect
(
child:
snackBarTransition
);
return
Hero
(
child:
ClipRect
(
child:
snackBarTransition
),
tag:
'<SnackBar Hero tag -
${widget.content}
>'
,
);
}
}
packages/flutter/lib/src/widgets/animated_list.dart
View file @
64c845c5
...
...
@@ -510,6 +510,7 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
/// class _SliverAnimatedListSampleState extends State<SliverAnimatedListSample> {
/// final GlobalKey<SliverAnimatedListState> _listKey = GlobalKey<SliverAnimatedListState>();
/// final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
/// final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
/// ListModel<int> _list;
/// int _selectedItem;
/// int _nextItem; // The next item inserted when the user presses the '+' button.
...
...
@@ -567,7 +568,7 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
/// _selectedItem = null;
/// });
/// } else {
/// _scaffoldKey.currentState.showSnackBar(SnackBar(
/// _scaffold
Messenger
Key.currentState.showSnackBar(SnackBar(
/// content: Text(
/// 'Select an item to remove from the list.',
/// style: TextStyle(fontSize: 20),
...
...
@@ -579,6 +580,7 @@ class AnimatedListState extends State<AnimatedList> with TickerProviderStateMixi
/// @override
/// Widget build(BuildContext context) {
/// return MaterialApp(
/// scaffoldMessengerKey: _scaffoldMessengerKey,
/// home: Scaffold(
/// key: _scaffoldKey,
/// body: CustomScrollView(
...
...
packages/flutter/lib/src/widgets/framework.dart
View file @
64c845c5
...
...
@@ -2112,33 +2112,52 @@ typedef ElementVisitor = void Function(Element element);
/// widget can be used: the build context passed to the [Builder.builder]
/// callback will be that of the [Builder] itself.
///
/// For example, in the following snippet, the [ScaffoldState.show
SnackBar
]
/// For example, in the following snippet, the [ScaffoldState.show
BottomSheet
]
/// method is called on the [Scaffold] widget that the build method itself
/// creates. If a [Builder] had not been used, and instead the `context`
/// argument of the build method itself had been used, no [Scaffold] would have
/// been found, and the [Scaffold.of] function would have returned null.
///
/// ```dart
/// @override
/// Widget build(BuildContext context) {
/// // here, Scaffold.of(context) returns null
/// return Scaffold(
/// appBar: AppBar(title: Text('Demo')),
/// body: Builder(
/// builder: (BuildContext context) {
/// return TextButton(
/// child: Text('BUTTON'),
/// onPressed: () {
/// // here, Scaffold.of(context) returns the locally created Scaffold
/// Scaffold.of(context).showSnackBar(SnackBar(
/// content: Text('Hello.')
/// ));
/// }
/// );
/// }
/// )
/// );
/// }
/// @override
/// Widget build(BuildContext context) {
/// // here, Scaffold.of(context) returns null
/// return Scaffold(
/// appBar: const AppBar(title: Text('Demo')),
/// body: Builder(
/// builder: (BuildContext context) {
/// return TextButton(
/// child: const Text('BUTTON'),
/// onPressed: () {
/// Scaffold.of(context).showBottomSheet<void>(
/// (BuildContext context) {
/// return Container(
/// alignment: Alignment.center,
/// height: 200,
/// color: Colors.amber,
/// child: Center(
/// child: Column(
/// mainAxisSize: MainAxisSize.min,
/// children: <Widget>[
/// const Text('BottomSheet'),
/// ElevatedButton(
/// child: const Text('Close BottomSheet'),
/// onPressed: () {
/// Navigator.pop(context),
/// },
/// )
/// ],
/// ),
/// ),
/// );
/// },
/// );
/// },
/// );
/// },
/// )
/// );
/// }
/// ```
///
/// The [BuildContext] for a particular widget can change location over time as
...
...
packages/flutter/test/material/debug_test.dart
View file @
64c845c5
...
...
@@ -168,6 +168,8 @@ void main() {
' _InheritedTheme
\n
'
' Theme
\n
'
' AnimatedTheme
\n
'
' _ScaffoldMessengerScope
\n
'
' ScaffoldMessenger
\n
'
' Builder
\n
'
' DefaultTextStyle
\n
'
' CustomPaint
\n
'
...
...
@@ -204,4 +206,83 @@ void main() {
' or WidgetsApp widget at the top of your application widget tree.
\n
'
,
));
});
testWidgets
(
'debugCheckHasScaffoldMessenger control test'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
ScaffoldState
>
_scaffoldKey
=
GlobalKey
<
ScaffoldState
>();
final
GlobalKey
<
ScaffoldMessengerState
>
_scaffoldMessengerKey
=
GlobalKey
<
ScaffoldMessengerState
>();
final
SnackBar
snackBar
=
SnackBar
(
content:
const
Text
(
'Snack'
),
action:
SnackBarAction
(
label:
'Test'
,
onPressed:
()
{})
);
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
ScaffoldMessenger
(
key:
_scaffoldMessengerKey
,
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
Scaffold
(
key:
_scaffoldKey
,
body:
Container
(),
);
}
)
),
)
));
final
List
<
dynamic
>
exceptions
=
<
dynamic
>[];
final
FlutterExceptionHandler
oldHandler
=
FlutterError
.
onError
;
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
exceptions
.
add
(
details
.
exception
);
};
// ScaffoldMessenger shows SnackBar.
_scaffoldMessengerKey
.
currentState
.
showSnackBar
(
snackBar
);
await
tester
.
pumpAndSettle
();
// Pump widget to rebuild without ScaffoldMessenger
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Scaffold
(
key:
_scaffoldKey
,
body:
Container
(),
),
),
));
// The Scaffold should assert we still have an ancestor ScaffoldMessenger in
// order to dismiss the SnackBar from the ScaffoldMessenger.
await
tester
.
tap
(
find
.
text
(
'Test'
));
FlutterError
.
onError
=
oldHandler
;
expect
(
exceptions
.
length
,
1
);
expect
(
exceptions
.
single
.
runtimeType
,
FlutterError
);
final
FlutterError
error
=
exceptions
.
first
as
FlutterError
;
expect
(
error
.
diagnostics
.
length
,
5
);
expect
(
error
.
diagnostics
[
2
],
isA
<
DiagnosticsProperty
<
Element
>>());
expect
(
error
.
diagnostics
[
3
],
isA
<
DiagnosticsBlock
>());
expect
(
error
.
diagnostics
[
4
].
level
,
DiagnosticLevel
.
hint
);
expect
(
error
.
diagnostics
[
4
].
toStringDeep
(),
equalsIgnoringHashCodes
(
'Typically, the ScaffoldMessenger widget is introduced by the
\n
'
'MaterialApp at the top of your application widget tree.
\n
'
,
),
);
expect
(
error
.
toStringDeep
(),
equalsIgnoringHashCodes
(
'FlutterError
\n
'
' No ScaffoldMessenger widget found.
\n
'
' Scaffold widgets require a ScaffoldMessenger widget ancestor.
\n
'
' The specific widget that could not find a ScaffoldMessenger
\n
'
' ancestor was:
\n
'
' Scaffold-[LabeledGlobalKey<ScaffoldState>#00829]
\n
'
' The ancestors of this widget were:
\n
'
' MediaQuery
\n
'
' Directionality
\n
'
' [root]
\n
'
' Typically, the ScaffoldMessenger widget is introduced by the
\n
'
' MaterialApp at the top of your application widget tree.
\n
'
));
});
}
packages/flutter/test/material/floating_action_button_location_test.dart
View file @
64c845c5
...
...
@@ -649,7 +649,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
FloatingActionButton
(
onPressed:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
'Snacky!'
)),
);
},
...
...
packages/flutter/test/material/scaffold_test.dart
View file @
64c845c5
...
...
@@ -2034,6 +2034,117 @@ void main() {
await
tester
.
pumpAndSettle
();
});
});
testWidgets
(
'ScaffoldMessenger.of can return null'
,
(
WidgetTester
tester
)
async
{
ScaffoldMessengerState
scaffoldMessenger
;
const
Key
tapTarget
=
Key
(
'tap-target'
);
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Scaffold
(
body:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
scaffoldMessenger
=
ScaffoldMessenger
.
of
(
context
,
nullOk:
true
);
},
behavior:
HitTestBehavior
.
opaque
,
child:
Container
(
height:
100.0
,
width:
100.0
,
key:
tapTarget
,
),
);
}
),
),
),
));
await
tester
.
tap
(
find
.
byKey
(
tapTarget
));
await
tester
.
pump
();
expect
(
scaffoldMessenger
,
isNull
);
});
testWidgets
(
'ScaffoldMessenger.of will assert if !nullOk'
,
(
WidgetTester
tester
)
async
{
const
Key
tapTarget
=
Key
(
'tap-target'
);
final
List
<
dynamic
>
exceptions
=
<
dynamic
>[];
final
FlutterExceptionHandler
oldHandler
=
FlutterError
.
onError
;
FlutterError
.
onError
=
(
FlutterErrorDetails
details
)
{
exceptions
.
add
(
details
.
exception
);
};
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Scaffold
(
body:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
ScaffoldMessenger
.
of
(
context
);
},
behavior:
HitTestBehavior
.
opaque
,
child:
Container
(
height:
100.0
,
width:
100.0
,
key:
tapTarget
,
),
);
}
),
),
),
));
await
tester
.
tap
(
find
.
byKey
(
tapTarget
));
FlutterError
.
onError
=
oldHandler
;
expect
(
exceptions
.
length
,
1
);
expect
(
exceptions
.
single
.
runtimeType
,
FlutterError
);
final
FlutterError
error
=
exceptions
.
first
as
FlutterError
;
expect
(
error
.
diagnostics
.
length
,
5
);
expect
(
error
.
diagnostics
[
2
],
isA
<
DiagnosticsProperty
<
Element
>>());
expect
(
error
.
diagnostics
[
3
],
isA
<
DiagnosticsBlock
>());
expect
(
error
.
diagnostics
[
4
].
level
,
DiagnosticLevel
.
hint
);
expect
(
error
.
diagnostics
[
4
].
toStringDeep
(),
equalsIgnoringHashCodes
(
'Typically, the ScaffoldMessenger widget is introduced by the
\n
'
'MaterialApp at the top of your application widget tree.
\n
'
,
),
);
expect
(
error
.
toStringDeep
(),
equalsIgnoringHashCodes
(
'FlutterError
\n
'
' No ScaffoldMessenger widget found.
\n
'
' Builder widgets require a ScaffoldMessenger widget ancestor.
\n
'
' The specific widget that could not find a ScaffoldMessenger
\n
'
' ancestor was:
\n
'
' Builder
\n
'
' The ancestors of this widget were:
\n
'
' _BodyBuilder
\n
'
' MediaQuery
\n
'
' LayoutId-[<_ScaffoldSlot.body>]
\n
'
' CustomMultiChildLayout
\n
'
' AnimatedBuilder
\n
'
' DefaultTextStyle
\n
'
' AnimatedDefaultTextStyle
\n
'
' _InkFeatures-[GlobalKey#342d0 ink renderer]
\n
'
' NotificationListener<LayoutChangedNotification>
\n
'
' PhysicalModel
\n
'
' AnimatedPhysicalModel
\n
'
' Material
\n
'
' PrimaryScrollController
\n
'
' _ScaffoldScope
\n
'
' Scaffold
\n
'
' MediaQuery
\n
'
' Directionality
\n
'
' [root]
\n
'
' Typically, the ScaffoldMessenger widget is introduced by the
\n
'
' MaterialApp at the top of your application widget tree.
\n
'
));
});
}
class
_GeometryListener
extends
StatefulWidget
{
...
...
packages/flutter/test/material/snack_bar_test.dart
View file @
64c845c5
This diff is collapsed.
Click to expand it.
packages/flutter/test/material/snack_bar_theme_test.dart
View file @
64c845c5
...
...
@@ -73,7 +73,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
text
),
duration:
const
Duration
(
seconds:
2
),
action:
SnackBarAction
(
label:
'ACTION'
,
onPressed:
()
{}),
...
...
@@ -111,7 +111,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
text
),
duration:
const
Duration
(
seconds:
2
),
action:
SnackBarAction
(
label:
action
,
onPressed:
()
{}),
...
...
@@ -155,7 +155,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
backgroundColor:
backgroundColor
,
elevation:
elevation
,
shape:
shape
,
...
...
@@ -202,7 +202,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
action:
SnackBarAction
(
label:
'ACTION'
,
onPressed:
()
{}),
...
...
@@ -244,7 +244,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
action:
SnackBarAction
(
label:
'ACTION'
,
onPressed:
()
{}),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment