[flutter roll] replicate the revert in release branch (#101947)
* accept all incoming
* Update debug_test.dart
* Update debug_test.dart
Co-authored-by: Kate Lovett <katelovett@google.com>
diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart
index 65bd565..086095c 100644
--- a/packages/flutter/lib/src/material/app_bar.dart
+++ b/packages/flutter/lib/src/material/app_bar.dart
@@ -737,24 +737,24 @@
static const double _defaultElevation = 4.0;
static const Color _defaultShadowColor = Color(0xFF000000);
- ScrollMetricsNotificationObserverState? _scrollMetricsNotificationObserver;
+ ScrollNotificationObserverState? _scrollNotificationObserver;
bool _scrolledUnder = false;
@override
void didChangeDependencies() {
super.didChangeDependencies();
- if (_scrollMetricsNotificationObserver != null)
- _scrollMetricsNotificationObserver!.removeListener(_handleScrollMetricsNotification);
- _scrollMetricsNotificationObserver = ScrollMetricsNotificationObserver.of(context);
- if (_scrollMetricsNotificationObserver != null)
- _scrollMetricsNotificationObserver!.addListener(_handleScrollMetricsNotification);
+ if (_scrollNotificationObserver != null)
+ _scrollNotificationObserver!.removeListener(_handleScrollNotification);
+ _scrollNotificationObserver = ScrollNotificationObserver.of(context);
+ if (_scrollNotificationObserver != null)
+ _scrollNotificationObserver!.addListener(_handleScrollNotification);
}
@override
void dispose() {
- if (_scrollMetricsNotificationObserver != null) {
- _scrollMetricsNotificationObserver!.removeListener(_handleScrollMetricsNotification);
- _scrollMetricsNotificationObserver = null;
+ if (_scrollNotificationObserver != null) {
+ _scrollNotificationObserver!.removeListener(_handleScrollNotification);
+ _scrollNotificationObserver = null;
}
super.dispose();
}
@@ -767,34 +767,18 @@
Scaffold.of(context).openEndDrawer();
}
- void _handleScrollMetricsNotification(ScrollMetricsNotification notification) {
- final bool oldScrolledUnder = _scrolledUnder;
- final ScrollMetrics metrics = notification.metrics;
-
- if (notification.depth != 0) {
- _scrolledUnder = false;
- } else {
- switch (metrics.axisDirection) {
- case AxisDirection.up:
- // Scroll view is reversed
- _scrolledUnder = metrics.extentAfter > 0;
- break;
- case AxisDirection.down:
- _scrolledUnder = metrics.extentBefore > 0;
- break;
- case AxisDirection.right:
- case AxisDirection.left:
- // Scrolled under is only supported in the vertical axis.
- _scrolledUnder = false;
- break;
+ void _handleScrollNotification(ScrollNotification notification) {
+ if (notification is ScrollUpdateNotification) {
+ final bool oldScrolledUnder = _scrolledUnder;
+ _scrolledUnder = notification.depth == 0
+ && notification.metrics.extentBefore > 0
+ && notification.metrics.axis == Axis.vertical;
+ if (_scrolledUnder != oldScrolledUnder) {
+ setState(() {
+ // React to a change in MaterialState.scrolledUnder
+ });
}
}
-
- if (_scrolledUnder != oldScrolledUnder) {
- setState(() {
- // React to a change in MaterialState.scrolledUnder
- });
- }
}
Color _resolveColor(Set<MaterialState> states, Color? widgetColor, Color? themeColor, Color defaultColor) {
diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart
index edd0b95..e5114c1 100644
--- a/packages/flutter/lib/src/material/scaffold.dart
+++ b/packages/flutter/lib/src/material/scaffold.dart
@@ -3096,7 +3096,7 @@
return _ScaffoldScope(
hasDrawer: hasDrawer,
geometryNotifier: _geometryNotifier,
- child: ScrollMetricsNotificationObserver(
+ child: ScrollNotificationObserver(
child: Material(
color: widget.backgroundColor ?? themeData.scaffoldBackgroundColor,
child: AnimatedBuilder(animation: _floatingActionButtonMoveController, builder: (BuildContext context, Widget? child) {
diff --git a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart
index bb51e1d..7829cbd 100644
--- a/packages/flutter/lib/src/widgets/scroll_notification_observer.dart
+++ b/packages/flutter/lib/src/widgets/scroll_notification_observer.dart
@@ -9,7 +9,6 @@
import 'framework.dart';
import 'notification_listener.dart';
import 'scroll_notification.dart';
-import 'scroll_position.dart';
/// A [ScrollNotification] listener for [ScrollNotificationObserver].
///
@@ -173,170 +172,3 @@
super.dispose();
}
}
-
-/// A [ScrollMetricsNotification] listener for [ScrollMetricsNotificationObserver].
-///
-/// [ScrollMetricsNotificationObserver] is similar to
-/// [NotificationListener]. It supports a listener list instead of
-/// just a single listener and its listeners run unconditionally, they
-/// do not require a gating boolean return value.
-typedef ScrollMetricsNotificationCallback = void Function(ScrollMetricsNotification notification);
-
-class _ScrollMetricsNotificationObserverScope extends InheritedWidget {
- const _ScrollMetricsNotificationObserverScope({
- Key? key,
- required Widget child,
- required ScrollMetricsNotificationObserverState scrollMetricsNotificationObserverState,
- }) : _scrollMetricsNotificationObserverState = scrollMetricsNotificationObserverState,
- super(key: key, child: child);
-
- final ScrollMetricsNotificationObserverState _scrollMetricsNotificationObserverState;
-
- @override
- bool updateShouldNotify(_ScrollMetricsNotificationObserverScope old) {
- return _scrollMetricsNotificationObserverState != old._scrollMetricsNotificationObserverState;
- }
-}
-
-class _MetricsListenerEntry extends LinkedListEntry<_MetricsListenerEntry> {
- _MetricsListenerEntry(this.listener);
- final ScrollMetricsNotificationCallback listener;
-}
-
-/// Notifies its listeners when a descendant ScrollMetrics are
-/// initialized or updated.
-///
-/// To add a listener to a [ScrollMetricsNotificationObserver] ancestor:
-/// ```dart
-/// void listener(ScrollMetricsNotification notification) {
-/// // Do something, maybe setState()
-/// }
-/// ScrollMetricsNotificationObserver.of(context).addListener(listener)
-/// ```
-///
-/// To remove the listener from a [ScrollMetricsNotificationObserver] ancestor:
-/// ```dart
-/// ScrollMetricsNotificationObserver.of(context).removeListener(listener);
-/// ```
-///
-/// Stateful widgets that share an ancestor [ScrollMetricsNotificationObserver]
-/// typically add a listener in [State.didChangeDependencies] (removing the old
-/// one if necessary) and remove the listener in their [State.dispose] method.
-///
-/// This widget is similar to [NotificationListener]. It supports
-/// a listener list instead of just a single listener and its listeners
-/// run unconditionally, they do not require a gating boolean return value.
-class ScrollMetricsNotificationObserver extends StatefulWidget {
- /// Create a [ScrollMetricsNotificationObserver].
- ///
- /// The [child] parameter must not be null.
- const ScrollMetricsNotificationObserver({
- Key? key,
- required this.child,
- }) : assert(child != null), super(key: key);
-
- /// The subtree below this widget.
- final Widget child;
-
- /// The closest instance of this class that encloses the given context.
- ///
- /// If there is no enclosing [ScrollMetricsNotificationObserver] widget, then
- /// null is returned.
- static ScrollMetricsNotificationObserverState? of(BuildContext context) {
- return context.dependOnInheritedWidgetOfExactType<_ScrollMetricsNotificationObserverScope>()?._scrollMetricsNotificationObserverState;
- }
-
- @override
- ScrollMetricsNotificationObserverState createState() => ScrollMetricsNotificationObserverState();
-}
-
-/// The listener list state for a [ScrollMetricsNotificationObserver] returned
-/// by [ScrollMetricsNotificationObserver.of].
-///
-/// [ScrollMetricsNotificationObserver] is similar to
-/// [NotificationListener]. It supports a listener list instead of
-/// just a single listener and its listeners run unconditionally, they
-/// do not require a gating boolean return value.
-class ScrollMetricsNotificationObserverState extends State<ScrollMetricsNotificationObserver> {
- LinkedList<_MetricsListenerEntry>? _listeners = LinkedList<_MetricsListenerEntry>();
-
- bool _debugAssertNotDisposed() {
- assert(() {
- if (_listeners == null) {
- throw FlutterError(
- 'A $runtimeType was used after being disposed.\n'
- 'Once you have called dispose() on a $runtimeType, it can no longer be used.',
- );
- }
- return true;
- }());
- return true;
- }
-
- /// Add a [ScrollMetricsNotificationCallback] that will be called each time
- /// a descendant scrolls.
- void addListener(ScrollMetricsNotificationCallback listener) {
- assert(_debugAssertNotDisposed());
- _listeners!.add(_MetricsListenerEntry(listener));
- }
-
- /// Remove the specified [ScrollMetricsNotificationCallback].
- void removeListener(ScrollMetricsNotificationCallback listener) {
- assert(_debugAssertNotDisposed());
- for (final _MetricsListenerEntry entry in _listeners!) {
- if (entry.listener == listener) {
- entry.unlink();
- return;
- }
- }
- }
-
- void _notifyListeners(ScrollMetricsNotification notification) {
- assert(_debugAssertNotDisposed());
- if (_listeners!.isEmpty)
- return;
-
- final List<_MetricsListenerEntry> localListeners = List<_MetricsListenerEntry>.of(_listeners!);
- for (final _MetricsListenerEntry entry in localListeners) {
- try {
- if (entry.list != null)
- entry.listener(notification);
- } catch (exception, stack) {
- FlutterError.reportError(FlutterErrorDetails(
- exception: exception,
- stack: stack,
- library: 'widget library',
- context: ErrorDescription('while dispatching notifications for $runtimeType'),
- informationCollector: () => <DiagnosticsNode>[
- DiagnosticsProperty<ScrollMetricsNotificationObserverState>(
- 'The $runtimeType sending notification was',
- this,
- style: DiagnosticsTreeStyle.errorProperty,
- ),
- ],
- ));
- }
- }
- }
-
- @override
- Widget build(BuildContext context) {
- return NotificationListener<ScrollMetricsNotification>(
- onNotification: (ScrollMetricsNotification notification) {
- _notifyListeners(notification);
- return false;
- },
- child: _ScrollMetricsNotificationObserverScope(
- scrollMetricsNotificationObserverState: this,
- child: widget.child,
- ),
- );
- }
-
- @override
- void dispose() {
- assert(_debugAssertNotDisposed());
- _listeners = null;
- super.dispose();
- }
-}
diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart
index 2c95313..3f78736 100644
--- a/packages/flutter/test/material/app_bar_test.dart
+++ b/packages/flutter/test/material/app_bar_test.dart
@@ -2568,457 +2568,311 @@
expect(actionIconTheme.color, foregroundColor);
});
- group('MaterialStateColor scrolledUnder', () {
+ testWidgets('SliverAppBar.backgroundColor MaterialStateColor scrolledUnder', (WidgetTester tester) async {
const double collapsedHeight = kToolbarHeight;
const double expandedHeight = 200.0;
const Color scrolledColor = Color(0xff00ff00);
const Color defaultColor = Color(0xff0000ff);
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ body: CustomScrollView(
+ slivers: <Widget>[
+ SliverAppBar(
+ elevation: 0,
+ backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
+ return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
+ }),
+ expandedHeight: expandedHeight,
+ pinned: true,
+ ),
+ SliverList(
+ delegate: SliverChildListDelegate(
+ <Widget>[
+ Container(height: 1200.0, color: Colors.teal),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+
Finder findAppBarMaterial() {
- return find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first;
+ return find.descendant(of: find.byType(AppBar), matching: find.byType(Material));
}
- Color? getAppBarBackgroundColor(WidgetTester tester) {
+ Color? getAppBarBackgroundColor() {
return tester.widget<Material>(findAppBarMaterial()).color;
}
- group('SliverAppBar', () {
- Widget _buildSliverApp({
- required double contentHeight,
- bool reverse = false,
- bool includeFlexibleSpace = false,
- }) {
- return MaterialApp(
- home: Scaffold(
- body: CustomScrollView(
- reverse: reverse,
- slivers: <Widget>[
- SliverAppBar(
- elevation: 0,
- backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
- return states.contains(MaterialState.scrolledUnder)
- ? scrolledColor
- : defaultColor;
- }),
- expandedHeight: expandedHeight,
- pinned: true,
- flexibleSpace: includeFlexibleSpace
- ? const FlexibleSpaceBar(title: Text('SliverAppBar'))
- : null,
- ),
- SliverList(
- delegate: SliverChildListDelegate(
- <Widget>[
- Container(height: contentHeight, color: Colors.teal),
- ],
- ),
- ),
- ],
- ),
- ),
- );
- }
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- testWidgets('backgroundColor', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(contentHeight: 1200.0)
- );
+ TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(0.0, -expandedHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
+ expect(getAppBarBackgroundColor(), scrolledColor);
+ expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, -expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
+ gesture = await tester.startGesture(const Offset(50.0, 300.0));
+ await gesture.moveBy(const Offset(0.0, expandedHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
+ });
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
+ testWidgets('SliverAppBar.backgroundColor with FlexibleSpace MaterialStateColor scrolledUnder', (WidgetTester tester) async {
+ const double collapsedHeight = kToolbarHeight;
+ const double expandedHeight = 200.0;
+ const Color scrolledColor = Color(0xff00ff00);
+ const Color defaultColor = Color(0xff0000ff);
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
-
- testWidgets('backgroundColor with FlexibleSpace', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(contentHeight: 1200.0, includeFlexibleSpace: true)
- );
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, -expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
-
- testWidgets('backgroundColor - reverse', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(contentHeight: 1200.0, reverse: true)
- );
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, -expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
-
- testWidgets('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(
- contentHeight: 1200.0,
- reverse: true,
- includeFlexibleSpace: true,
- )
- );
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, -expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
-
- testWidgets('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(contentHeight: 200, reverse: true)
- );
-
- // In reverse, the content here is not long enough to scroll under the app
- // bar.
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
-
- final TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
-
- testWidgets('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildSliverApp(
- contentHeight: 200,
- reverse: true,
- includeFlexibleSpace: true,
- )
- );
-
- // In reverse, the content here is not long enough to scroll under the app
- // bar.
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
-
- final TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, expandedHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
- });
- });
-
- group('AppBar', () {
- Widget _buildAppBar({
- required double contentHeight,
- bool reverse = false,
- bool includeFlexibleSpace = false
- }) {
- return MaterialApp(
- home: Scaffold(
- appBar: AppBar(
- elevation: 0,
- backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
- return states.contains(MaterialState.scrolledUnder)
- ? scrolledColor
- : defaultColor;
- }),
- title: const Text('AppBar'),
- flexibleSpace: includeFlexibleSpace
- ? const FlexibleSpaceBar(title: Text('FlexibleSpace'))
- : null,
- ),
- body: ListView(
- reverse: reverse,
- children: <Widget>[
- Container(height: contentHeight, color: Colors.teal),
- ],
- ),
- ),
- );
- }
-
- testWidgets('backgroundColor', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(contentHeight: 1200.0)
- );
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
-
- testWidgets('backgroundColor with FlexibleSpace', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(contentHeight: 1200.0, includeFlexibleSpace: true)
- );
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
-
- testWidgets('backgroundColor - reverse', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(contentHeight: 1200.0, reverse: true)
- );
- await tester.pump();
-
- // In this test case, the content always extends under the AppBar, so it
- // should always be the scrolledColor.
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
-
- testWidgets('backgroundColor with FlexibleSpace - reverse', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(
- contentHeight: 1200.0,
- reverse: true,
- includeFlexibleSpace: true,
- )
- );
- await tester.pump();
-
- // In this test case, the content always extends under the AppBar, so it
- // should always be the scrolledColor.
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
-
- gesture = await tester.startGesture(const Offset(50.0, 300.0));
- await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
-
- expect(getAppBarBackgroundColor(tester), scrolledColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
-
- testWidgets('_handleScrollMetricsNotification safely calls setState()', (WidgetTester tester) async {
- // Regression test for failures found in Google internal issue b/185192049.
- final ScrollController controller = ScrollController(initialScrollOffset: 400);
- await tester.pumpWidget(
- MaterialApp(
- home: Scaffold(
- appBar: AppBar(
- title: const Text('AppBar'),
- ),
- body: Scrollbar(
- isAlwaysShown: true,
- controller: controller,
- child: ListView(
- controller: controller,
- children: <Widget>[
- Container(height: 1200.0, color: Colors.teal),
- ],
- ),
- ),
- ),
- ),
- );
-
- expect(tester.takeException(), isNull);
- });
-
- testWidgets('does not trigger on horizontal scroll', (WidgetTester tester) async {
- await tester.pumpWidget(
- MaterialApp(
- home: Scaffold(
- appBar: AppBar(
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ body: CustomScrollView(
+ slivers: <Widget>[
+ SliverAppBar(
elevation: 0,
backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
- return states.contains(MaterialState.scrolledUnder)
- ? scrolledColor
- : defaultColor;
+ return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
}),
- title: const Text('AppBar'),
+ expandedHeight: expandedHeight,
+ pinned: true,
+ flexibleSpace: const FlexibleSpaceBar(
+ title: Text('SliverAppBar'),
+ ),
),
- body: ListView(
- scrollDirection: Axis.horizontal,
- children: <Widget>[
- Container(height: 600.0, width: 1200.0, color: Colors.teal),
- ],
+ SliverList(
+ delegate: SliverChildListDelegate(
+ <Widget>[
+ Container(height: 1200.0, color: Colors.teal),
+ ],
+ ),
),
+ ],
+ ),
+ ),
+ ),
+ );
+
+ Finder findAppBarMaterial() {
+ // There are 2 Material widgets below AppBar. The second is only added if
+ // flexibleSpace is non-null.
+ return find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first;
+ }
+
+ Color? getAppBarBackgroundColor() {
+ return tester.widget<Material>(findAppBarMaterial()).color;
+ }
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
+
+ TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(0.0, -expandedHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), scrolledColor);
+ expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
+
+ gesture = await tester.startGesture(const Offset(50.0, 300.0));
+ await gesture.moveBy(const Offset(0.0, expandedHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
+ });
+
+ testWidgets('AppBar.backgroundColor MaterialStateColor scrolledUnder', (WidgetTester tester) async {
+ const Color scrolledColor = Color(0xff00ff00);
+ const Color defaultColor = Color(0xff0000ff);
+
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
+ return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
+ }),
+ title: const Text('AppBar'),
+ ),
+ body: ListView(
+ children: <Widget>[
+ Container(height: 1200.0, color: Colors.teal),
+ ],
+ ),
+ ),
+ ),
+ );
+
+ Finder findAppBarMaterial() {
+ return find.descendant(of: find.byType(AppBar), matching: find.byType(Material));
+ }
+
+ Color? getAppBarBackgroundColor() {
+ return tester.widget<Material>(findAppBarMaterial()).color;
+ }
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+
+ TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), scrolledColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+
+ gesture = await tester.startGesture(const Offset(50.0, 300.0));
+ await gesture.moveBy(const Offset(0.0, kToolbarHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+ });
+
+ testWidgets('AppBar.backgroundColor with FlexibleSpace MaterialStateColor scrolledUnder', (WidgetTester tester) async {
+ const Color scrolledColor = Color(0xff00ff00);
+ const Color defaultColor = Color(0xff0000ff);
+
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
+ return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
+ }),
+ title: const Text('AppBar'),
+ flexibleSpace: const FlexibleSpaceBar(
+ title: Text('FlexibleSpace'),
),
),
- );
+ body: ListView(
+ children: <Widget>[
+ Container(height: 1200.0, color: Colors.teal),
+ ],
+ ),
+ ),
+ ),
+ );
- expect(getAppBarBackgroundColor(tester), defaultColor);
+ Finder findAppBarMaterial() {
+ // There are 2 Material widgets below AppBar. The second is only added if
+ // flexibleSpace is non-null.
+ return find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first;
+ }
- TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(-100.0, 0.0));
- await gesture.up();
- await tester.pumpAndSettle();
+ Color? getAppBarBackgroundColor() {
+ return tester.widget<Material>(findAppBarMaterial()).color;
+ }
- expect(getAppBarBackgroundColor(tester), defaultColor);
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(100.0, 0.0));
- await gesture.up();
- await tester.pumpAndSettle();
+ TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(0.0, -kToolbarHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
- expect(getAppBarBackgroundColor(tester), defaultColor);
- });
+ expect(getAppBarBackgroundColor(), scrolledColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- testWidgets('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(
- contentHeight: 200.0,
- reverse: true,
- )
- );
- await tester.pump();
+ gesture = await tester.startGesture(const Offset(50.0, 300.0));
+ await gesture.moveBy(const Offset(0.0, kToolbarHeight));
+ await gesture.up();
+ await tester.pumpAndSettle();
- // In reverse, the content here is not long enough to scroll under the app
- // bar.
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+ expect(getAppBarBackgroundColor(), defaultColor);
+ expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+ });
- final TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
+ testWidgets('AppBar._handleScrollNotification safely calls setState()', (WidgetTester tester) async {
+ // Regression test for failures found in Google internal issue b/185192049.
+ final ScrollController controller = ScrollController(initialScrollOffset: 400);
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ title: const Text('AppBar'),
+ ),
+ body: Scrollbar(
+ isAlwaysShown: true,
+ controller: controller,
+ child: ListView(
+ controller: controller,
+ children: <Widget>[
+ Container(height: 1200.0, color: Colors.teal),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
+ expect(tester.takeException(), isNull);
+ });
- testWidgets('backgroundColor with FlexibleSpace - not triggered in reverse for short content', (WidgetTester tester) async {
- await tester.pumpWidget(
- _buildAppBar(
- contentHeight: 200.0,
- reverse: true,
- includeFlexibleSpace: true,
- )
- );
- await tester.pump();
+ testWidgets('AppBar scrolledUnder does not trigger on horizontal scroll', (WidgetTester tester) async {
+ const Color scrolledColor = Color(0xff00ff00);
+ const Color defaultColor = Color(0xff0000ff);
- // In reverse, the content here is not long enough to scroll under the app
- // bar.
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ elevation: 0,
+ backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
+ return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
+ }),
+ title: const Text('AppBar'),
+ ),
+ body: ListView(
+ scrollDirection: Axis.horizontal,
+ children: <Widget>[
+ Container(height: 600.0, width: 1200.0, color: Colors.teal),
+ ],
+ ),
+ ),
+ ),
+ );
- final TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
- await gesture.moveBy(const Offset(0.0, kToolbarHeight));
- await gesture.up();
- await tester.pumpAndSettle();
+ Finder findAppBarMaterial() {
+ return find.descendant(of: find.byType(AppBar), matching: find.byType(Material));
+ }
- expect(getAppBarBackgroundColor(tester), defaultColor);
- expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
- });
- });
+ Color? getAppBarBackgroundColor() {
+ return tester.widget<Material>(findAppBarMaterial()).color;
+ }
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+
+ TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(-100.0, 0.0));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), defaultColor);
+
+ gesture = await tester.startGesture(const Offset(50.0, 400.0));
+ await gesture.moveBy(const Offset(100.0, 0.0));
+ await gesture.up();
+ await tester.pumpAndSettle();
+
+ expect(getAppBarBackgroundColor(), defaultColor);
});
testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async {
diff --git a/packages/flutter/test/material/scaffold_test.dart b/packages/flutter/test/material/scaffold_test.dart
index 759853e..9cb32cd 100644
--- a/packages/flutter/test/material/scaffold_test.dart
+++ b/packages/flutter/test/material/scaffold_test.dart
@@ -2302,9 +2302,9 @@
' PhysicalModel\n'
' AnimatedPhysicalModel\n'
' Material\n'
- ' _ScrollMetricsNotificationObserverScope\n'
- ' NotificationListener<ScrollMetricsNotification>\n'
- ' ScrollMetricsNotificationObserver\n'
+ ' _ScrollNotificationObserverScope\n'
+ ' NotificationListener<ScrollNotification>\n'
+ ' ScrollNotificationObserver\n'
' _ScaffoldScope\n'
' Scaffold\n'
' MediaQuery\n'