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
adc5f26b
Unverified
Commit
adc5f26b
authored
Sep 08, 2020
by
Hans Muller
Committed by
GitHub
Sep 08, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Re-land ScaffoldMessenger (#65416)
parent
c0675577
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
820 additions
and
302 deletions
+820
-302
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
+483
-152
snack_bar.dart
packages/flutter/lib/src/material/snack_bar.dart
+20
-18
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
+48
-0
floating_action_button_location_test.dart
...r/test/material/floating_action_button_location_test.dart
+1
-1
snack_bar_test.dart
packages/flutter/test/material/snack_bar_test.dart
+152
-81
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 @
adc5f26b
...
...
@@ -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
...
...
@@ -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
,
...
...
@@ -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
,
...
...
@@ -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
;
...
...
@@ -722,7 +733,9 @@ class _MaterialAppState extends State<MaterialApp> {
}
theme
??=
widget
.
theme
??
ThemeData
.
light
();
return
AnimatedTheme
(
return
ScaffoldMessenger
(
key:
widget
.
scaffoldMessengerKey
,
child:
AnimatedTheme
(
data:
theme
,
isMaterialAppTheme:
true
,
child:
widget
.
builder
!=
null
...
...
@@ -743,6 +756,7 @@ class _MaterialAppState extends State<MaterialApp> {
},
)
:
child
,
)
);
}
...
...
packages/flutter/lib/src/material/app_bar.dart
View file @
adc5f26b
...
...
@@ -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(
...
...
packages/flutter/lib/src/material/debug.dart
View file @
adc5f26b
...
...
@@ -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.
///
...
...
@@ -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
;
}
packages/flutter/lib/src/material/scaffold.dart
View file @
adc5f26b
...
...
@@ -19,6 +19,7 @@ import 'bottom_sheet.dart';
import
'button_bar.dart'
;
import
'colors.dart'
;
import
'curves.dart'
;
import
'debug.dart'
;
import
'divider.dart'
;
import
'drawer.dart'
;
import
'flexible_space_bar.dart'
;
...
...
@@ -61,6 +62,372 @@ enum _ScaffoldSlot {
statusBar
,
}
/// Manages [SnackBar]s for descendant [Scaffold]s.
///
/// This class provides APIs for showing snack bars.
///
/// To display a snack bar, obtain the [ScaffoldMessengerState] for the current
/// [BuildContext] via [ScaffoldMessenger.of] and use the
/// [ScaffoldMessengerState.showSnackBar] function.
///
/// See also:
///
/// * [SnackBar], which is a temporary notification typically shown near the
/// bottom of the app using the [ScaffoldMessengerState.showSnackBar] method.
/// * Cookbook: [Display a snackbar](https://flutter.dev/docs/cookbook/design/snackbars)
class
ScaffoldMessenger
extends
StatefulWidget
{
/// Creates a widget that manages [SnackBar]s for [Scaffold] descendants.
const
ScaffoldMessenger
({
Key
key
,
@required
this
.
child
,
})
:
assert
(
child
!=
null
),
super
(
key:
key
);
/// The widget below this widget in the tree.
///
/// {@macro flutter.widgets.child}
final
Widget
child
;
/// The state from the closest instance of this class that encloses the given
/// context.
///
/// {@tool dartpad --template=stateless_widget_scaffold_center}
/// Typical usage of the [ScaffoldMessenger.of] function is to call it in
/// response to a user gesture or an application state change.
///
/// ```dart
/// Widget build(BuildContext context) {
/// return ElevatedButton(
/// child: const Text('SHOW A SNACKBAR'),
/// onPressed: () {
/// ScaffoldMessenger.of(context).showSnackBar(
/// const SnackBar(
/// content: Text('Have a snack!'),
/// ),
/// );
/// },
/// );
/// }
/// ```
/// {@end-tool}
///
/// A less elegant but more expedient solution is assign a [GlobalKey] to the
/// [ScaffoldMessenger], then use the `key.currentState` property to obtain the
/// [ScaffoldMessengerState] rather than using the [ScaffoldMessenger.of]
/// function. The [MaterialApp.scaffoldMessengerKey] refers to the root
/// ScaffoldMessenger that is provided by default.
///
/// {@tool dartpad --template=freeform}
/// Sometimes [SnackBar]s are produced by code that doesn't have ready access
/// to a valid [BuildContext]. One such example of this is when you may want
/// to show a SnackBar from a method outside of the `build` function. In these
/// cases, you can assign a [GlobalKey] to the [ScaffoldMessenger]. This
/// example shows a key being used to obtain the [ScaffoldMessengerState]
/// provided by the [MaterialApp].
///
/// ```dart imports
/// import 'package:flutter/material.dart';
/// ```
/// ```dart
/// void main() => runApp(MyApp());
///
/// class MyApp extends StatefulWidget {
/// @override
/// _MyAppState createState() => _MyAppState();
/// }
///
/// class _MyAppState extends State<MyApp> {
/// final GlobalKey<ScaffoldMessengerState> _scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
/// int _counter = 0;
///
/// void _incrementCounter() {
/// setState(() {
/// _counter++;
/// });
/// if (_counter % 10 == 0) {
/// _scaffoldMessengerKey.currentState.showSnackBar(const SnackBar(
/// content: Text('A multiple of ten!'),
/// ));
/// }
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return MaterialApp(
/// scaffoldMessengerKey: _scaffoldMessengerKey,
/// home: Scaffold(
/// appBar: AppBar(title: Text('ScaffoldMessenger Demo')),
/// body: Center(
/// child: Column(
/// mainAxisAlignment: MainAxisAlignment.center,
/// children: <Widget>[
/// Text(
/// 'You have pushed the button this many times:',
/// ),
/// Text(
/// '$_counter',
/// style: Theme.of(context).textTheme.headline4,
/// ),
/// ],
/// ),
/// ),
/// floatingActionButton: FloatingActionButton(
/// onPressed: _incrementCounter,
/// tooltip: 'Increment',
/// child: Icon(Icons.add),
/// ),
/// ),
/// );
/// }
/// }
///
/// ```
/// {@end-tool}
///
/// If there is no [ScaffoldMessenger] in scope, then this will throw an
/// exception.
static
ScaffoldMessengerState
of
(
BuildContext
context
)
{
assert
(
context
!=
null
);
final
_ScaffoldMessengerScope
scope
=
context
.
dependOnInheritedWidgetOfExactType
<
_ScaffoldMessengerScope
>();
return
scope
?.
_scaffoldMessengerState
;
}
@override
ScaffoldMessengerState
createState
()
=>
ScaffoldMessengerState
();
}
/// State for a [ScaffoldMessenger].
///
/// A [ScaffoldMessengerState] object can be used to [showSnackBar] for every
/// registered [Scaffold] that is a descendant of the associated
/// [ScaffoldMessenger]. Scaffolds will register to receive [SnackBar]s from
/// their closest ScaffoldMessenger ancestor.
///
/// Typically obtained via [ScaffoldMessenger.of].
class
ScaffoldMessengerState
extends
State
<
ScaffoldMessenger
>
with
TickerProviderStateMixin
{
final
LinkedHashSet
<
ScaffoldState
>
_scaffolds
=
LinkedHashSet
<
ScaffoldState
>();
final
Queue
<
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>>
_snackBars
=
Queue
<
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>>();
AnimationController
_snackBarController
;
Timer
_snackBarTimer
;
bool
_accessibleNavigation
;
@override
void
didChangeDependencies
()
{
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
// If we transition from accessible navigation to non-accessible navigation
// and there is a SnackBar that would have timed out that has already
// completed its timer, dismiss that SnackBar. If the timer hasn't finished
// yet, let it timeout as normal.
if
(
_accessibleNavigation
==
true
&&
!
mediaQuery
.
accessibleNavigation
&&
_snackBarTimer
!=
null
&&
!
_snackBarTimer
.
isActive
)
{
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
timeout
);
}
_accessibleNavigation
=
mediaQuery
.
accessibleNavigation
;
super
.
didChangeDependencies
();
}
void
_register
(
ScaffoldState
scaffold
)
{
_scaffolds
.
add
(
scaffold
);
if
(
_snackBars
.
isNotEmpty
)
{
scaffold
.
_updateSnackBar
();
}
}
void
_unregister
(
ScaffoldState
scaffold
)
{
final
bool
removed
=
_scaffolds
.
remove
(
scaffold
);
// ScaffoldStates should only be removed once.
assert
(
removed
);
}
/// Shows a [SnackBar] across all registered [Scaffold]s.
///
/// A scaffold can show at most one snack bar at a time. If this function is
/// called while another snack bar is already visible, the given snack bar
/// will be added to a queue and displayed after the earlier snack bars have
/// closed.
///
/// To control how long a [SnackBar] remains visible, use [SnackBar.duration].
///
/// To remove the [SnackBar] with an exit animation, use [hideCurrentSnackBar]
/// or call [ScaffoldFeatureController.close] on the returned
/// [ScaffoldFeatureController]. To remove a [SnackBar] suddenly (without an
/// animation), use [removeCurrentSnackBar].
///
/// See [ScaffoldMessenger.of] for information about how to obtain the
/// [ScaffoldMessengerState].
///
/// {@tool dartpad --template=stateless_widget_scaffold_center}
///
/// Here is an example of showing a [SnackBar] when the user presses a button.
///
/// ```dart
/// Widget build(BuildContext context) {
/// return OutlinedButton(
/// onPressed: () {
/// ScaffoldMessenger.of(context).showSnackBar(
/// const SnackBar(
/// content: Text('A SnackBar has been shown.'),
/// ),
/// );
/// },
/// child: const Text('Show SnackBar'),
/// );
/// }
/// ```
/// {@end-tool}
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>
showSnackBar
(
SnackBar
snackBar
)
{
_snackBarController
??=
SnackBar
.
createAnimationController
(
vsync:
this
)
..
addStatusListener
(
_handleStatusChanged
);
if
(
_snackBars
.
isEmpty
)
{
assert
(
_snackBarController
.
isDismissed
);
_snackBarController
.
forward
();
}
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>
controller
;
controller
=
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>.
_
(
// We provide a fallback key so that if back-to-back snackbars happen to
// match in structure, material ink splashes and highlights don't survive
// from one to the next.
snackBar
.
withAnimation
(
_snackBarController
,
fallbackKey:
UniqueKey
()),
Completer
<
SnackBarClosedReason
>(),
()
{
assert
(
_snackBars
.
first
==
controller
);
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
hide
);
},
null
,
// SnackBar doesn't use a builder function so setState() wouldn't rebuild it
);
setState
(()
{
_snackBars
.
addLast
(
controller
);
});
_updateScaffolds
();
return
controller
;
}
void
_handleStatusChanged
(
AnimationStatus
status
)
{
switch
(
status
)
{
case
AnimationStatus
.
dismissed
:
assert
(
_snackBars
.
isNotEmpty
);
setState
(()
{
_snackBars
.
removeFirst
();
});
_updateScaffolds
();
if
(
_snackBars
.
isNotEmpty
)
{
_snackBarController
.
forward
();
}
break
;
case
AnimationStatus
.
completed
:
setState
(()
{
assert
(
_snackBarTimer
==
null
);
// build will create a new timer if necessary to dismiss the snackBar.
});
_updateScaffolds
();
break
;
case
AnimationStatus
.
forward
:
break
;
case
AnimationStatus
.
reverse
:
break
;
}
}
void
_updateScaffolds
()
{
for
(
final
ScaffoldState
scaffold
in
_scaffolds
)
{
scaffold
.
_updateSnackBar
();
}
}
/// Removes the current [SnackBar] (if any) immediately from registered
/// [Scaffold]s.
///
/// The removed snack bar does not run its normal exit animation. If there are
/// any queued snack bars, they begin their entrance animation immediately.
void
removeCurrentSnackBar
({
SnackBarClosedReason
reason
=
SnackBarClosedReason
.
remove
})
{
assert
(
reason
!=
null
);
if
(
_snackBars
.
isEmpty
)
return
;
final
Completer
<
SnackBarClosedReason
>
completer
=
_snackBars
.
first
.
_completer
;
if
(!
completer
.
isCompleted
)
completer
.
complete
(
reason
);
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
// This will trigger the animation's status callback.
_snackBarController
.
value
=
0.0
;
}
/// Removes the current [SnackBar] by running its normal exit animation.
///
/// The closed completer is called after the animation is complete.
void
hideCurrentSnackBar
({
SnackBarClosedReason
reason
=
SnackBarClosedReason
.
hide
})
{
assert
(
reason
!=
null
);
if
(
_snackBars
.
isEmpty
||
_snackBarController
.
status
==
AnimationStatus
.
dismissed
)
return
;
final
Completer
<
SnackBarClosedReason
>
completer
=
_snackBars
.
first
.
_completer
;
if
(
_accessibleNavigation
)
{
_snackBarController
.
value
=
0.0
;
completer
.
complete
(
reason
);
}
else
{
_snackBarController
.
reverse
().
then
<
void
>((
void
value
)
{
assert
(
mounted
);
if
(!
completer
.
isCompleted
)
completer
.
complete
(
reason
);
});
}
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
}
@override
Widget
build
(
BuildContext
context
)
{
assert
(
debugCheckHasMediaQuery
(
context
));
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
_accessibleNavigation
=
mediaQuery
.
accessibleNavigation
;
if
(
_snackBars
.
isNotEmpty
)
{
final
ModalRoute
<
dynamic
>
route
=
ModalRoute
.
of
(
context
);
if
(
route
==
null
||
route
.
isCurrent
)
{
if
(
_snackBarController
.
isCompleted
&&
_snackBarTimer
==
null
)
{
final
SnackBar
snackBar
=
_snackBars
.
first
.
_widget
;
_snackBarTimer
=
Timer
(
snackBar
.
duration
,
()
{
assert
(
_snackBarController
.
status
==
AnimationStatus
.
forward
||
_snackBarController
.
status
==
AnimationStatus
.
completed
);
// Look up MediaQuery again in case the setting changed.
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
if
(
mediaQuery
.
accessibleNavigation
&&
snackBar
.
action
!=
null
)
return
;
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
timeout
);
});
}
}
}
return
_ScaffoldMessengerScope
(
scaffoldMessengerState:
this
,
child:
widget
.
child
,
);
}
@override
void
dispose
()
{
_snackBarController
?.
dispose
();
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
super
.
dispose
();
}
}
class
_ScaffoldMessengerScope
extends
InheritedWidget
{
const
_ScaffoldMessengerScope
({
Key
key
,
Widget
child
,
ScaffoldMessengerState
scaffoldMessengerState
,
})
:
_scaffoldMessengerState
=
scaffoldMessengerState
,
super
(
key:
key
,
child:
child
);
final
ScaffoldMessengerState
_scaffoldMessengerState
;
@override
bool
updateShouldNotify
(
_ScaffoldMessengerScope
old
)
=>
_scaffoldMessengerState
!=
old
.
_scaffoldMessengerState
;
}
/// The geometry of the [Scaffold] after all its contents have been laid out
/// except the [FloatingActionButton].
///
...
...
@@ -837,11 +1204,11 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
/// Implements the basic material design visual layout structure.
///
/// This class provides APIs for showing drawers
, snack bars,
and bottom sheets.
/// This class provides APIs for showing drawers and bottom sheets.
///
/// To display a
snackbar or a
persistent bottom sheet, obtain the
/// To display a persistent bottom sheet, obtain the
/// [ScaffoldState] for the current [BuildContext] via [Scaffold.of] and use the
/// [ScaffoldState.show
SnackBar] and [ScaffoldState.showBottomSheet] functions
.
/// [ScaffoldState.show
BottomSheet] function
.
///
/// {@tool dartpad --template=stateful_widget_material}
/// This example shows a [Scaffold] with a [body] and [FloatingActionButton].
...
...
@@ -918,7 +1285,7 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
/// Widget build(BuildContext context) {
/// return Scaffold(
/// appBar: AppBar(
/// title: Text('Sample Code'),
/// title:
const
Text('Sample Code'),
/// ),
/// body: Center(
/// child: Text('You have pressed the button $_count times.'),
...
...
@@ -1006,8 +1373,6 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
/// * [BottomNavigationBar], which is a horizontal array of buttons typically
/// shown along the bottom of the app using the [bottomNavigationBar]
/// property.
/// * [SnackBar], which is a temporary notification typically shown near the
/// bottom of the app using the [ScaffoldState.showSnackBar] method.
/// * [BottomSheet], which is an overlay typically shown near the bottom of the
/// app. A bottom sheet can either be persistent, in which case it is shown
/// using the [ScaffoldState.showBottomSheet] method, or modal, in which case
...
...
@@ -1015,7 +1380,6 @@ class _FloatingActionButtonTransitionState extends State<_FloatingActionButtonTr
/// * [ScaffoldState], which is the state associated with this widget.
/// * <https://material.io/design/layout/responsive-layout-grid.html>
/// * Cookbook: [Add a Drawer to a screen](https://flutter.dev/docs/cookbook/design/drawer)
/// * Cookbook: [Display a snackbar](https://flutter.dev/docs/cookbook/design/snackbars)
/// * See our
/// [Scaffold Sample Apps](https://flutter.dev/docs/catalog/samples/Scaffold).
class
Scaffold
extends
StatefulWidget
{
...
...
@@ -1387,7 +1751,7 @@ class Scaffold extends StatefulWidget {
/// ),
/// home: Scaffold(
/// body: MyScaffoldBody(),
/// appBar: AppBar(title: Text('Scaffold.of Example')),
/// appBar: AppBar(title:
const
Text('Scaffold.of Example')),
/// ),
/// color: Colors.white,
/// );
...
...
@@ -1401,14 +1765,32 @@ class Scaffold extends StatefulWidget {
/// Widget build(BuildContext context) {
/// return Center(
/// child: ElevatedButton(
/// child:
Text('SHOW A SNACKBAR
'),
/// child:
const Text('SHOW BOTTOM SHEET
'),
/// onPressed: () {
/// Scaffold.of(context).showSnackBar(
/// SnackBar(
/// content: Text('Have a snack!'),
/// 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);
/// },
/// )
/// ],
/// ),
/// ),
/// );
/// },
/// );
/// },
/// ),
/// );
/// }
...
...
@@ -1427,20 +1809,38 @@ class Scaffold extends StatefulWidget {
/// ```dart
/// Widget build(BuildContext context) {
/// return Scaffold(
/// appBar: AppBar(
/// title: Text('Demo')
/// ),
/// appBar: AppBar(title: const Text('Demo')),
/// body: Builder(
/// // Create an inner BuildContext so that the onPressed methods
/// // can refer to the Scaffold with Scaffold.of().
/// builder: (BuildContext context) {
/// return Center(
/// child: ElevatedButton(
/// child:
Text('SHOW A SNACKBAR
'),
/// child:
const Text('SHOW BOTTOM SHEET
'),
/// onPressed: () {
/// Scaffold.of(context).showSnackBar(SnackBar(
/// content: Text('Have a snack!'),
/// ));
/// 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);
/// },
/// )
/// ],
/// ),
/// ),
/// );
/// },
/// );
/// },
/// ),
/// );
...
...
@@ -1557,7 +1957,7 @@ class Scaffold extends StatefulWidget {
/// See also:
///
/// * [Scaffold.of], which provides access to the [ScaffoldState] object as a
/// whole, from which you can show
snackbars,
bottom sheets, and so forth.
/// whole, from which you can show bottom sheets, and so forth.
static
bool
hasDrawer
(
BuildContext
context
,
{
bool
registerForUpdates
=
true
})
{
assert
(
registerForUpdates
!=
null
);
assert
(
context
!=
null
);
...
...
@@ -1576,8 +1976,8 @@ class Scaffold extends StatefulWidget {
/// State for a [Scaffold].
///
/// Can display [
SnackBar]s and [BottomSheet]s. Retrieve a [ScaffoldState] from
///
the current
[BuildContext] using [Scaffold.of].
/// Can display [
BottomSheet]s. Retrieve a [ScaffoldState] from the current
/// [BuildContext] using [Scaffold.of].
class
ScaffoldState
extends
State
<
Scaffold
>
with
TickerProviderStateMixin
{
// DRAWER API
...
...
@@ -1668,12 +2068,10 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
// SNACKBAR API
final
Queue
<
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>>
_snackBars
=
Queue
<
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>>();
AnimationController
_snackBarController
;
Timer
_snackBarTimer
;
bool
_accessibleNavigation
;
ScaffoldMessengerState
_scaffoldMessenger
;
/// Shows a [SnackBar] at the bottom of the scaffold.
/// [ScaffoldMessengerState.showSnackBar] shows a [SnackBar] at the bottom of
/// the scaffold. This method should not be used.
///
/// A scaffold can show at most one snack bar at a time. If this function is
/// called while another snack bar is already visible, the given snack bar
...
...
@@ -1682,12 +2080,14 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
///
/// To control how long a [SnackBar] remains visible, use [SnackBar.duration].
///
/// To remove the [SnackBar] with an exit animation, use [hideCurrentSnackBar]
/// or call [ScaffoldFeatureController.close] on the returned
/// [ScaffoldFeatureController]. To remove a [SnackBar] suddenly (without an
/// animation), use [removeCurrentSnackBar].
/// To remove the [SnackBar] with an exit animation, use
/// [ScaffoldMessengerState.hideCurrentSnackBar] or call
/// [ScaffoldFeatureController.close] on the returned [ScaffoldFeatureController].
/// To remove a [SnackBar] suddenly (without an animation), use
/// [ScaffoldMessengerState.removeCurrentSnackBar].
///
/// See [Scaffold.of] for information about how to obtain the [ScaffoldState].
/// See [ScaffoldMessenger.of] for information about how to obtain the
/// [ScaffoldMessengerState].
///
/// {@tool dartpad --template=stateless_widget_scaffold_center}
///
...
...
@@ -1697,104 +2097,66 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
/// Widget build(BuildContext context) {
/// return OutlinedButton(
/// onPressed: () {
/// Scaffold.of(context).showSnackBar(
/// Scaffold
Messenger
.of(context).showSnackBar(
/// SnackBar(
/// content: Text('A SnackBar has been shown.'),
/// content:
const
Text('A SnackBar has been shown.'),
/// ),
/// );
/// },
/// child: Text('Show SnackBar'),
/// child:
const
Text('Show SnackBar'),
/// );
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [ScaffoldMessenger], this should be used instead to manage [SnackBar]s.
// TODO(Piinks): Deprecate after customers are migrated
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>
showSnackBar
(
SnackBar
snackbar
)
{
_snackBarController
??=
SnackBar
.
createAnimationController
(
vsync:
this
)
..
addStatusListener
(
_handleSnackBarStatusChange
);
if
(
_snackBars
.
isEmpty
)
{
assert
(
_snackBarController
.
isDismissed
);
_snackBarController
.
forward
();
}
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>
controller
;
controller
=
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>.
_
(
// We provide a fallback key so that if back-to-back snackbars happen to
// match in structure, material ink splashes and highlights don't survive
// from one to the next.
snackbar
.
withAnimation
(
_snackBarController
,
fallbackKey:
UniqueKey
()),
Completer
<
SnackBarClosedReason
>(),
()
{
assert
(
_snackBars
.
first
==
controller
);
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
hide
);
},
null
,
// SnackBar doesn't use a builder function so setState() wouldn't rebuild it
);
setState
(()
{
_snackBars
.
addLast
(
controller
);
});
return
controller
;
assert
(
debugCheckHasScaffoldMessenger
(
context
));
return
_scaffoldMessenger
.
showSnackBar
(
snackbar
);
}
void
_handleSnackBarStatusChange
(
AnimationStatus
status
)
{
switch
(
status
)
{
case
AnimationStatus
.
dismissed
:
assert
(
_snackBars
.
isNotEmpty
);
setState
(()
{
_snackBars
.
removeFirst
();
});
if
(
_snackBars
.
isNotEmpty
)
_snackBarController
.
forward
();
break
;
case
AnimationStatus
.
completed
:
setState
(()
{
assert
(
_snackBarTimer
==
null
);
// build will create a new timer if necessary to dismiss the snack bar
});
break
;
case
AnimationStatus
.
forward
:
case
AnimationStatus
.
reverse
:
break
;
}
}
/// Removes the current [SnackBar] (if any) immediately.
/// [ScaffoldMessengerState.removeCurrentSnackBar] removes the current
/// [SnackBar] (if any) immediately. This method should not be used.
///
/// The removed snack bar does not run its normal exit animation. If there are
/// any queued snack bars, they begin their entrance animation immediately.
///
/// See also:
///
/// * [ScaffoldMessenger], this should be used instead to manage [SnackBar]s.
// TODO(Piinks): Deprecate after customers are migrated
void
removeCurrentSnackBar
({
SnackBarClosedReason
reason
=
SnackBarClosedReason
.
remove
})
{
assert
(
reason
!=
null
);
if
(
_snackBars
.
isEmpty
)
return
;
final
Completer
<
SnackBarClosedReason
>
completer
=
_snackBars
.
first
.
_completer
;
if
(!
completer
.
isCompleted
)
completer
.
complete
(
reason
);
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
_snackBarController
.
value
=
0.0
;
assert
(
debugCheckHasScaffoldMessenger
(
context
));
_scaffoldMessenger
.
removeCurrentSnackBar
(
reason:
reason
);
}
/// Removes the current [SnackBar] by running its normal exit animation.
/// [ScaffoldMessengerState.hideCurrentSnackBar] removes the current
/// [SnackBar] by running its normal exit animation. This method should not be
/// used.
///
/// The closed completer is called after the animation is complete.
///
/// See also:
///
/// * [ScaffoldMessenger], this should be used instead to manage [SnackBar]s.
// TODO(Piinks): Deprecate after customers are migrated.
void
hideCurrentSnackBar
({
SnackBarClosedReason
reason
=
SnackBarClosedReason
.
hide
})
{
assert
(
reason
!=
null
);
if
(
_snackBars
.
isEmpty
||
_snackBarController
.
status
==
AnimationStatus
.
dismissed
)
return
;
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
final
Completer
<
SnackBarClosedReason
>
completer
=
_snackBars
.
first
.
_completer
;
if
(
mediaQuery
.
accessibleNavigation
)
{
_snackBarController
.
value
=
0.0
;
completer
.
complete
(
reason
);
}
else
{
_snackBarController
.
reverse
().
then
<
void
>((
void
value
)
{
assert
(
mounted
);
if
(!
completer
.
isCompleted
)
completer
.
complete
(
reason
);
});
}
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
assert
(
debugCheckHasScaffoldMessenger
(
context
));
_scaffoldMessenger
.
hideCurrentSnackBar
(
reason:
reason
);
}
ScaffoldFeatureController
<
SnackBar
,
SnackBarClosedReason
>
_snackBar
;
void
_updateSnackBar
()
{
setState
(()
{
_snackBar
=
_scaffoldMessenger
.
_snackBars
.
isNotEmpty
?
_scaffoldMessenger
.
_snackBars
.
first
:
null
;
});
}
// PERSISTENT BOTTOM SHEET API
...
...
@@ -2016,7 +2378,9 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
/// const Text('BottomSheet'),
/// ElevatedButton(
/// child: const Text('Close BottomSheet'),
/// onPressed: () => Navigator.pop(context),
/// onPressed: () {
/// Navigator.pop(context);
/// }
/// )
/// ],
/// ),
...
...
@@ -2204,27 +2568,14 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
@override
void
didChangeDependencies
()
{
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
// If we transition from accessible navigation to non-accessible navigation
// and there is a SnackBar that would have timed out that has already
// completed its timer, dismiss that SnackBar. If the timer hasn't finished
// yet, let it timeout as normal.
if
(
_accessibleNavigation
==
true
&&
!
mediaQuery
.
accessibleNavigation
&&
_snackBarTimer
!=
null
&&
!
_snackBarTimer
.
isActive
)
{
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
timeout
);
}
_accessibleNavigation
=
mediaQuery
.
accessibleNavigation
;
_scaffoldMessenger
=
ScaffoldMessenger
.
of
(
context
);
_scaffoldMessenger
?.
_register
(
this
);
_maybeBuildPersistentBottomSheet
();
super
.
didChangeDependencies
();
}
@override
void
dispose
()
{
_snackBarController
?.
dispose
();
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
_geometryNotifier
.
dispose
();
for
(
final
_StandardBottomSheet
bottomSheet
in
_dismissedBottomSheets
)
{
bottomSheet
.
animationController
?.
dispose
();
...
...
@@ -2234,6 +2585,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
}
_floatingActionButtonMoveController
.
dispose
();
_floatingActionButtonVisibilityController
.
dispose
();
_scaffoldMessenger
?.
_unregister
(
this
);
super
.
dispose
();
}
...
...
@@ -2347,28 +2699,6 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
final
ThemeData
themeData
=
Theme
.
of
(
context
);
final
TextDirection
textDirection
=
Directionality
.
of
(
context
);
_accessibleNavigation
=
mediaQuery
.
accessibleNavigation
;
if
(
_snackBars
.
isNotEmpty
)
{
final
ModalRoute
<
dynamic
>
route
=
ModalRoute
.
of
(
context
);
if
(
route
==
null
||
route
.
isCurrent
)
{
if
(
_snackBarController
.
isCompleted
&&
_snackBarTimer
==
null
)
{
final
SnackBar
snackBar
=
_snackBars
.
first
.
_widget
;
_snackBarTimer
=
Timer
(
snackBar
.
duration
,
()
{
assert
(
_snackBarController
.
status
==
AnimationStatus
.
forward
||
_snackBarController
.
status
==
AnimationStatus
.
completed
);
// Look up MediaQuery again in case the setting changed.
final
MediaQueryData
mediaQuery
=
MediaQuery
.
of
(
context
);
if
(
mediaQuery
.
accessibleNavigation
&&
snackBar
.
action
!=
null
)
return
;
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
timeout
);
});
}
}
else
{
_snackBarTimer
?.
cancel
();
_snackBarTimer
=
null
;
}
}
final
List
<
LayoutId
>
children
=
<
LayoutId
>[];
_addIfNonNull
(
...
...
@@ -2423,16 +2753,16 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
bool
isSnackBarFloating
=
false
;
double
snackBarWidth
;
if
(
_snackBar
s
.
isNotEmpty
)
{
final
SnackBarBehavior
snackBarBehavior
=
_snackBar
s
.
first
.
_widget
.
behavior
if
(
_snackBar
!=
null
)
{
final
SnackBarBehavior
snackBarBehavior
=
_snackBar
.
_widget
.
behavior
??
themeData
.
snackBarTheme
.
behavior
??
SnackBarBehavior
.
fixed
;
isSnackBarFloating
=
snackBarBehavior
==
SnackBarBehavior
.
floating
;
snackBarWidth
=
_snackBar
s
.
first
.
_widget
.
width
;
snackBarWidth
=
_snackBar
.
_widget
.
width
;
_addIfNonNull
(
children
,
_snackBar
s
.
first
.
_widget
,
_snackBar
.
_widget
,
_ScaffoldSlot
.
snackBar
,
removeLeftPadding:
false
,
removeTopPadding:
true
,
...
...
@@ -2596,7 +2926,8 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
/// An interface for controlling a feature of a [Scaffold].
///
/// Commonly obtained from [ScaffoldState.showSnackBar] or [ScaffoldState.showBottomSheet].
/// Commonly obtained from [ScaffoldMessengerState.showSnackBar] or
/// [ScaffoldState.showBottomSheet].
class
ScaffoldFeatureController
<
T
extends
Widget
,
U
>
{
const
ScaffoldFeatureController
.
_
(
this
.
_widget
,
this
.
_completer
,
this
.
close
,
this
.
setState
);
final
T
_widget
;
...
...
packages/flutter/lib/src/material/snack_bar.dart
View file @
adc5f26b
...
...
@@ -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.
...
...
@@ -123,7 +123,7 @@ class _SnackBarActionState extends State<SnackBarAction> {
_haveTriggeredAction
=
true
;
});
widget
.
onPressed
();
Scaffold
.
of
(
context
).
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
action
);
Scaffold
Messenger
.
of
(
context
).
hideCurrentSnackBar
(
reason:
SnackBarClosedReason
.
action
);
}
@override
...
...
@@ -146,8 +146,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].
///
...
...
@@ -156,11 +156,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
...
...
@@ -289,7 +289,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>
...
...
@@ -301,7 +301,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
})
{
...
...
@@ -516,14 +516,14 @@ class _SnackBarState extends State<SnackBar> {
container:
true
,
liveRegion:
true
,
onDismiss:
()
{
Scaffold
.
of
(
context
).
removeCurrentSnackBar
(
reason:
SnackBarClosedReason
.
dismiss
);
Scaffold
Messenger
.
of
(
context
).
removeCurrentSnackBar
(
reason:
SnackBarClosedReason
.
dismiss
);
},
child:
Dismissible
(
key:
const
Key
(
'dismissible'
),
direction:
DismissDirection
.
down
,
resizeDuration:
null
,
onDismissed:
(
DismissDirection
direction
)
{
Scaffold
.
of
(
context
).
removeCurrentSnackBar
(
reason:
SnackBarClosedReason
.
swipe
);
Scaffold
Messenger
.
of
(
context
).
removeCurrentSnackBar
(
reason:
SnackBarClosedReason
.
swipe
);
},
child:
snackBar
,
),
...
...
@@ -550,7 +550,9 @@ class _SnackBarState extends State<SnackBar> {
child:
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 @
adc5f26b
...
...
@@ -512,6 +512,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.
...
...
@@ -569,7 +570,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),
...
...
@@ -581,6 +582,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 @
adc5f26b
...
...
@@ -2084,7 +2084,7 @@ 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
...
...
@@ -2101,13 +2101,32 @@ typedef ElementVisitor = void Function(Element element);
/// return TextButton(
/// child: Text('BUTTON'),
/// onPressed: () {
/// // here, Scaffold.of(context) returns the locally created Scaffold
/// Scaffold.of(context).showSnackBar(SnackBar(
/// content: Text('Hello.')
/// ));
/// }
/// 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),
/// },
/// )
/// ],
/// ),
/// ),
/// );
/// }
/// },
/// );
/// },
/// );
/// },
/// )
/// );
/// }
...
...
packages/flutter/test/material/debug_test.dart
View file @
adc5f26b
...
...
@@ -164,6 +164,8 @@ void main() {
' _InheritedTheme
\n
'
' Theme
\n
'
' AnimatedTheme
\n
'
' _ScaffoldMessengerScope
\n
'
' ScaffoldMessenger
\n
'
' Builder
\n
'
' DefaultTextStyle
\n
'
' CustomPaint
\n
'
...
...
@@ -196,4 +198,50 @@ 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
>();
await
tester
.
pumpWidget
(
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
MediaQuery
(
data:
const
MediaQueryData
(),
child:
Scaffold
(
key:
_scaffoldKey
,
body:
Container
(),
),
),
));
FlutterError
error
;
try
{
_scaffoldKey
.
currentState
.
showSnackBar
(
const
SnackBar
(
content:
Text
(
'Something is missing here'
)));
}
on
FlutterError
catch
(
e
)
{
error
=
e
;
}
finally
{
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>#d60fa]
\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 @
adc5f26b
...
...
@@ -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/snack_bar_test.dart
View file @
adc5f26b
...
...
@@ -18,7 +18,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
helloSnackBar
),
duration:
Duration
(
seconds:
2
),
));
...
...
@@ -64,7 +64,7 @@ void main() {
return
GestureDetector
(
onTap:
()
{
snackBarCount
+=
1
;
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
'bar
$snackBarCount
'
),
duration:
const
Duration
(
seconds:
2
),
));
...
...
@@ -141,7 +141,7 @@ void main() {
return
GestureDetector
(
onTap:
()
{
snackBarCount
+=
1
;
lastController
=
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
lastController
=
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
'bar
$snackBarCount
'
),
duration:
Duration
(
seconds:
time
),
));
...
...
@@ -225,7 +225,7 @@ void main() {
return
GestureDetector
(
onTap:
()
{
snackBarCount
+=
1
;
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
'bar
$snackBarCount
'
),
duration:
const
Duration
(
seconds:
2
),
));
...
...
@@ -268,7 +268,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
(
...
...
@@ -309,7 +309,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
...
...
@@ -351,7 +351,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
...
...
@@ -389,7 +389,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
margin:
const
EdgeInsets
.
all
(
padding
),
...
...
@@ -476,7 +476,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
'I am a snack bar.'
),
padding:
EdgeInsets
.
all
(
padding
),
...
...
@@ -520,7 +520,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
width:
width
,
...
...
@@ -558,7 +558,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
...
...
@@ -611,7 +611,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:
()
{
}),
...
...
@@ -666,7 +666,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:
()
{}),
...
...
@@ -717,7 +717,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:
()
{}),
...
...
@@ -771,7 +771,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:
()
{}),
...
...
@@ -829,7 +829,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:
()
{}),
...
...
@@ -861,18 +861,18 @@ void main() {
});
testWidgets
(
'SnackBarClosedReason'
,
(
WidgetTester
tester
)
async
{
final
GlobalKey
<
Scaffold
State
>
scaffoldKey
=
GlobalKey
<
Scaffold
State
>();
final
GlobalKey
<
Scaffold
MessengerState
>
scaffoldMessengerKey
=
GlobalKey
<
ScaffoldMessenger
State
>();
bool
actionPressed
=
false
;
SnackBarClosedReason
closedReason
;
await
tester
.
pumpWidget
(
MaterialApp
(
scaffoldMessengerKey:
scaffoldMessengerKey
,
home:
Scaffold
(
key:
scaffoldKey
,
body:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'snack'
),
duration:
const
Duration
(
seconds:
2
),
action:
SnackBarAction
(
...
...
@@ -917,14 +917,14 @@ void main() {
// Pop up the snack bar and then remove it.
await
tester
.
tap
(
find
.
text
(
'X'
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
750
));
scaffoldKey
.
currentState
.
removeCurrentSnackBar
();
scaffold
Messenger
Key
.
currentState
.
removeCurrentSnackBar
();
await
tester
.
pumpAndSettle
(
const
Duration
(
seconds:
1
));
expect
(
closedReason
,
equals
(
SnackBarClosedReason
.
remove
));
// Pop up the snack bar and then hide it.
await
tester
.
tap
(
find
.
text
(
'X'
));
await
tester
.
pump
(
const
Duration
(
milliseconds:
750
));
scaffoldKey
.
currentState
.
hideCurrentSnackBar
();
scaffold
Messenger
Key
.
currentState
.
hideCurrentSnackBar
();
await
tester
.
pumpAndSettle
(
const
Duration
(
seconds:
1
));
expect
(
closedReason
,
equals
(
SnackBarClosedReason
.
hide
));
...
...
@@ -944,13 +944,14 @@ void main() {
await
tester
.
pumpWidget
(
MaterialApp
(
home:
MediaQuery
(
data:
const
MediaQueryData
(
accessibleNavigation:
true
),
child:
Scaffold
(
key:
scaffoldKey
,
body:
Builder
(
child:
ScaffoldMessenger
(
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
return
Scaffold
(
key:
scaffoldKey
,
body:
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'snack'
),
duration:
const
Duration
(
seconds:
1
),
action:
SnackBarAction
(
...
...
@@ -960,9 +961,10 @@ void main() {
));
},
child:
const
Text
(
'X'
),
);
},
),
);
}
)
),
),
));
...
...
@@ -986,13 +988,13 @@ void main() {
await
tester
.
pumpWidget
(
MaterialApp
(
home:
MediaQuery
(
data:
const
MediaQueryData
(
accessibleNavigation:
true
),
child:
Scaffold
(
child:
ScaffoldMessenger
(
child:
Builder
(
builder:
(
BuildContext
context
)
{
return
Scaffold
(
key:
scaffoldKey
,
body:
Builder
(
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
body:
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'snack'
),
duration:
const
Duration
(
seconds:
1
),
action:
SnackBarAction
(
...
...
@@ -1002,11 +1004,11 @@ void main() {
));
},
child:
const
Text
(
'X'
),
);
},
),
),
);
}),
),
)
));
await
tester
.
tap
(
find
.
text
(
'X'
));
await
tester
.
pumpAndSettle
();
...
...
@@ -1031,7 +1033,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
helloSnackBar
),
));
},
...
...
@@ -1080,7 +1082,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'test'
),
action:
SnackBarAction
(
label:
'foo'
,
onPressed:
()
{
}),
));
...
...
@@ -1126,7 +1128,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
Text
(
nonconst
(
'hello'
)),
duration:
null
,
));
...
...
@@ -1156,7 +1158,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'hello'
),
duration:
const
Duration
(
seconds:
1
),
onVisible:
()
{
...
...
@@ -1193,14 +1195,14 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'hello'
),
duration:
const
Duration
(
seconds:
1
),
onVisible:
()
{
called
+=
1
;
},
));
Scaffold
.
of
(
context
).
showSnackBar
(
SnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'hello 2'
),
duration:
const
Duration
(
seconds:
1
),
onVisible:
()
{
...
...
@@ -1247,8 +1249,8 @@ void main() {
),
);
final
Scaffold
State
scaffoldState
=
tester
.
state
(
find
.
byType
(
Scaffold
));
scaffoldState
.
showSnackBar
(
snackBar
);
final
Scaffold
MessengerState
scaffoldMessengerState
=
tester
.
state
(
find
.
byType
(
ScaffoldMessenger
));
scaffold
Messenger
State
.
showSnackBar
(
snackBar
);
await
tester
.
pumpAndSettle
();
// Have the SnackBar fully animate out.
...
...
@@ -1278,8 +1280,8 @@ void main() {
),
);
final
Scaffold
State
scaffoldState
=
tester
.
state
(
find
.
byType
(
Scaffold
));
scaffoldState
.
showSnackBar
(
snackBar
);
final
Scaffold
MessengerState
scaffoldMessengerState
=
tester
.
state
(
find
.
byType
(
ScaffoldMessenger
));
scaffold
Messenger
State
.
showSnackBar
(
snackBar
);
await
tester
.
pumpAndSettle
();
// Have the SnackBar fully animate out.
...
...
@@ -1298,9 +1300,8 @@ void main() {
testWidgets
(
'Padding of
$behavior
is not consumed by viewInsets'
,
(
WidgetTester
tester
)
async
{
final
Widget
child
=
Directionality
(
textDirection:
TextDirection
.
ltr
,
child:
Scaffold
(
final
Widget
child
=
MaterialApp
(
home:
Scaffold
(
resizeToAvoidBottomInset:
false
,
floatingActionButton:
FloatingActionButton
(
child:
const
Icon
(
Icons
.
send
),
...
...
@@ -1310,7 +1311,7 @@ void main() {
builder:
(
BuildContext
context
)
{
return
GestureDetector
(
onTap:
()
{
Scaffold
.
of
(
context
).
showSnackBar
(
Scaffold
Messenger
.
of
(
context
).
showSnackBar
(
SnackBar
(
content:
const
Text
(
'I am a snack bar.'
),
duration:
const
Duration
(
seconds:
2
),
...
...
@@ -1374,8 +1375,8 @@ void main() {
),
);
final
Scaffold
State
scaffoldState
=
tester
.
state
(
find
.
byType
(
Scaffold
));
scaffoldState
.
showSnackBar
(
final
Scaffold
MessengerState
scaffoldMessengerState
=
tester
.
state
(
find
.
byType
(
ScaffoldMessenger
));
scaffold
Messenger
State
.
showSnackBar
(
const
SnackBar
(
content:
Text
(
'Snackbar text'
),
behavior:
SnackBarBehavior
.
fixed
,
...
...
@@ -1410,7 +1411,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:
()
{}),
...
...
@@ -1452,8 +1453,8 @@ void main() {
),
);
final
Scaffold
State
scaffoldState
=
tester
.
state
(
find
.
byType
(
Scaffold
));
scaffoldState
.
showSnackBar
(
final
Scaffold
MessengerState
scaffoldMessengerState
=
tester
.
state
(
find
.
byType
(
ScaffoldMessenger
));
scaffold
Messenger
State
.
showSnackBar
(
const
SnackBar
(
content:
Text
(
'SnackBar text'
),
behavior:
SnackBarBehavior
.
fixed
,
...
...
@@ -1489,8 +1490,8 @@ void main() {
),
);
final
Scaffold
State
scaffoldState
=
tester
.
state
(
find
.
byType
(
Scaffold
));
scaffoldState
.
showSnackBar
(
final
Scaffold
MessengerState
scaffoldMessengerState
=
tester
.
state
(
find
.
byType
(
ScaffoldMessenger
));
scaffold
Messenger
State
.
showSnackBar
(
const
SnackBar
(
content:
Text
(
'SnackBar text'
),
behavior:
SnackBarBehavior
.
floating
,
...
...
@@ -1506,4 +1507,74 @@ void main() {
},
);
});
testWidgets
(
'SnackBars hero across transitions'
,
(
WidgetTester
tester
)
async
{
const
String
snackBarText
=
'hello snackbar'
;
const
String
firstHeader
=
'home'
;
const
String
secondHeader
=
'second'
;
const
Key
snackTarget
=
Key
(
'snack-target'
);
const
Key
transitionTarget
=
Key
(
'transition-target'
);
Widget
_buildApp
()
{
return
MaterialApp
(
routes:
<
String
,
WidgetBuilder
>
{
'/'
:
(
BuildContext
context
)
{
return
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
firstHeader
)),
body:
Center
(
child:
ElevatedButton
(
key:
transitionTarget
,
child:
const
Text
(
'PUSH'
),
onPressed:
()
{
Navigator
.
of
(
context
).
pushNamed
(
'/second'
);
},
),
),
floatingActionButton:
FloatingActionButton
(
key:
snackTarget
,
onPressed:
()
async
{
ScaffoldMessenger
.
of
(
context
).
showSnackBar
(
const
SnackBar
(
content:
Text
(
snackBarText
),
),
);
},
child:
const
Text
(
'X'
),
),
);
},
'/second'
:
(
BuildContext
context
)
=>
Scaffold
(
appBar:
AppBar
(
title:
const
Text
(
secondHeader
)),
),
}
);
}
await
tester
.
pumpWidget
(
_buildApp
());
expect
(
find
.
text
(
snackBarText
),
findsNothing
);
expect
(
find
.
text
(
firstHeader
),
findsOneWidget
);
expect
(
find
.
text
(
secondHeader
),
findsNothing
);
// Present SnackBar
await
tester
.
tap
(
find
.
byKey
(
snackTarget
));
await
tester
.
pump
();
// schedule animation
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
await
tester
.
pump
();
// begin animation
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
750
));
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
// Push new route
await
tester
.
tap
(
find
.
byKey
(
transitionTarget
));
await
tester
.
pump
();
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
expect
(
find
.
text
(
firstHeader
),
findsOneWidget
);
expect
(
find
.
text
(
secondHeader
,
skipOffstage:
false
),
findsOneWidget
);
await
tester
.
pump
();
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
expect
(
find
.
text
(
firstHeader
),
findsOneWidget
);
expect
(
find
.
text
(
secondHeader
),
findsOneWidget
);
await
tester
.
pump
(
const
Duration
(
milliseconds:
750
));
expect
(
find
.
text
(
snackBarText
),
findsOneWidget
);
expect
(
find
.
text
(
firstHeader
),
findsNothing
);
expect
(
find
.
text
(
secondHeader
),
findsOneWidget
);
});
}
packages/flutter/test/material/snack_bar_theme_test.dart
View file @
adc5f26b
...
...
@@ -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:
()
{}),
...
...
@@ -110,7 +110,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:
()
{}),
...
...
@@ -153,7 +153,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
,
...
...
@@ -200,7 +200,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:
()
{}),
...
...
@@ -242,7 +242,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