Fix reverse cases for App Bar scrolled under behavior (#101460)
This commit is contained in:
parent
f5f9ad915e
commit
c7d2935077
@ -737,24 +737,24 @@ class _AppBarState extends State<AppBar> {
|
|||||||
static const double _defaultElevation = 4.0;
|
static const double _defaultElevation = 4.0;
|
||||||
static const Color _defaultShadowColor = Color(0xFF000000);
|
static const Color _defaultShadowColor = Color(0xFF000000);
|
||||||
|
|
||||||
ScrollNotificationObserverState? _scrollNotificationObserver;
|
ScrollMetricsNotificationObserverState? _scrollMetricsNotificationObserver;
|
||||||
bool _scrolledUnder = false;
|
bool _scrolledUnder = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
if (_scrollNotificationObserver != null)
|
if (_scrollMetricsNotificationObserver != null)
|
||||||
_scrollNotificationObserver!.removeListener(_handleScrollNotification);
|
_scrollMetricsNotificationObserver!.removeListener(_handleScrollMetricsNotification);
|
||||||
_scrollNotificationObserver = ScrollNotificationObserver.of(context);
|
_scrollMetricsNotificationObserver = ScrollMetricsNotificationObserver.of(context);
|
||||||
if (_scrollNotificationObserver != null)
|
if (_scrollMetricsNotificationObserver != null)
|
||||||
_scrollNotificationObserver!.addListener(_handleScrollNotification);
|
_scrollMetricsNotificationObserver!.addListener(_handleScrollMetricsNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (_scrollNotificationObserver != null) {
|
if (_scrollMetricsNotificationObserver != null) {
|
||||||
_scrollNotificationObserver!.removeListener(_handleScrollNotification);
|
_scrollMetricsNotificationObserver!.removeListener(_handleScrollMetricsNotification);
|
||||||
_scrollNotificationObserver = null;
|
_scrollMetricsNotificationObserver = null;
|
||||||
}
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@ -767,18 +767,34 @@ class _AppBarState extends State<AppBar> {
|
|||||||
Scaffold.of(context).openEndDrawer();
|
Scaffold.of(context).openEndDrawer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleScrollNotification(ScrollNotification notification) {
|
void _handleScrollMetricsNotification(ScrollMetricsNotification notification) {
|
||||||
if (notification is ScrollUpdateNotification) {
|
final bool oldScrolledUnder = _scrolledUnder;
|
||||||
final bool oldScrolledUnder = _scrolledUnder;
|
final ScrollMetrics metrics = notification.metrics;
|
||||||
_scrolledUnder = notification.depth == 0
|
|
||||||
&& notification.metrics.extentBefore > 0
|
if (notification.depth != 0) {
|
||||||
&& notification.metrics.axis == Axis.vertical;
|
_scrolledUnder = false;
|
||||||
if (_scrolledUnder != oldScrolledUnder) {
|
} else {
|
||||||
setState(() {
|
switch (metrics.axisDirection) {
|
||||||
// React to a change in MaterialState.scrolledUnder
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_scrolledUnder != oldScrolledUnder) {
|
||||||
|
setState(() {
|
||||||
|
// React to a change in MaterialState.scrolledUnder
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _resolveColor(Set<MaterialState> states, Color? widgetColor, Color? themeColor, Color defaultColor) {
|
Color _resolveColor(Set<MaterialState> states, Color? widgetColor, Color? themeColor, Color defaultColor) {
|
||||||
|
@ -3096,7 +3096,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin, Resto
|
|||||||
return _ScaffoldScope(
|
return _ScaffoldScope(
|
||||||
hasDrawer: hasDrawer,
|
hasDrawer: hasDrawer,
|
||||||
geometryNotifier: _geometryNotifier,
|
geometryNotifier: _geometryNotifier,
|
||||||
child: ScrollNotificationObserver(
|
child: ScrollMetricsNotificationObserver(
|
||||||
child: Material(
|
child: Material(
|
||||||
color: widget.backgroundColor ?? themeData.scaffoldBackgroundColor,
|
color: widget.backgroundColor ?? themeData.scaffoldBackgroundColor,
|
||||||
child: AnimatedBuilder(animation: _floatingActionButtonMoveController, builder: (BuildContext context, Widget? child) {
|
child: AnimatedBuilder(animation: _floatingActionButtonMoveController, builder: (BuildContext context, Widget? child) {
|
||||||
|
@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'framework.dart';
|
import 'framework.dart';
|
||||||
import 'notification_listener.dart';
|
import 'notification_listener.dart';
|
||||||
import 'scroll_notification.dart';
|
import 'scroll_notification.dart';
|
||||||
|
import 'scroll_position.dart';
|
||||||
|
|
||||||
/// A [ScrollNotification] listener for [ScrollNotificationObserver].
|
/// A [ScrollNotification] listener for [ScrollNotificationObserver].
|
||||||
///
|
///
|
||||||
@ -172,3 +173,170 @@ class ScrollNotificationObserverState extends State<ScrollNotificationObserver>
|
|||||||
super.dispose();
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2568,311 +2568,457 @@ void main() {
|
|||||||
expect(actionIconTheme.color, foregroundColor);
|
expect(actionIconTheme.color, foregroundColor);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('SliverAppBar.backgroundColor MaterialStateColor scrolledUnder', (WidgetTester tester) async {
|
group('MaterialStateColor scrolledUnder', () {
|
||||||
const double collapsedHeight = kToolbarHeight;
|
const double collapsedHeight = kToolbarHeight;
|
||||||
const double expandedHeight = 200.0;
|
const double expandedHeight = 200.0;
|
||||||
const Color scrolledColor = Color(0xff00ff00);
|
const Color scrolledColor = Color(0xff00ff00);
|
||||||
const Color defaultColor = Color(0xff0000ff);
|
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() {
|
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, 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('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);
|
|
||||||
|
|
||||||
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,
|
|
||||||
flexibleSpace: const FlexibleSpaceBar(
|
|
||||||
title: Text('SliverAppBar'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
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;
|
return find.descendant(of: find.byType(AppBar), matching: find.byType(Material)).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color? getAppBarBackgroundColor() {
|
Color? getAppBarBackgroundColor(WidgetTester tester) {
|
||||||
return tester.widget<Material>(findAppBarMaterial()).color;
|
return tester.widget<Material>(findAppBarMaterial()).color;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(getAppBarBackgroundColor(), defaultColor);
|
group('SliverAppBar', () {
|
||||||
expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
|
Widget _buildSliverApp({
|
||||||
|
required double contentHeight,
|
||||||
TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
bool reverse = false,
|
||||||
await gesture.moveBy(const Offset(0.0, -expandedHeight));
|
bool includeFlexibleSpace = false,
|
||||||
await gesture.up();
|
}) {
|
||||||
await tester.pumpAndSettle();
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
expect(getAppBarBackgroundColor(), scrolledColor);
|
body: CustomScrollView(
|
||||||
expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
|
reverse: reverse,
|
||||||
|
slivers: <Widget>[
|
||||||
gesture = await tester.startGesture(const Offset(50.0, 300.0));
|
SliverAppBar(
|
||||||
await gesture.moveBy(const Offset(0.0, expandedHeight));
|
elevation: 0,
|
||||||
await gesture.up();
|
backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
||||||
await tester.pumpAndSettle();
|
return states.contains(MaterialState.scrolledUnder)
|
||||||
|
? scrolledColor
|
||||||
expect(getAppBarBackgroundColor(), defaultColor);
|
: defaultColor;
|
||||||
expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
|
}),
|
||||||
});
|
expandedHeight: expandedHeight,
|
||||||
|
pinned: true,
|
||||||
testWidgets('AppBar.backgroundColor MaterialStateColor scrolledUnder', (WidgetTester tester) async {
|
flexibleSpace: includeFlexibleSpace
|
||||||
const Color scrolledColor = Color(0xff00ff00);
|
? const FlexibleSpaceBar(title: Text('SliverAppBar'))
|
||||||
const Color defaultColor = Color(0xff0000ff);
|
: null,
|
||||||
|
),
|
||||||
await tester.pumpWidget(
|
SliverList(
|
||||||
MaterialApp(
|
delegate: SliverChildListDelegate(
|
||||||
home: Scaffold(
|
<Widget>[
|
||||||
appBar: AppBar(
|
Container(height: contentHeight, color: Colors.teal),
|
||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
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, 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._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(tester.takeException(), isNull);
|
testWidgets('backgroundColor', (WidgetTester tester) async {
|
||||||
});
|
await tester.pumpWidget(
|
||||||
|
_buildSliverApp(contentHeight: 1200.0)
|
||||||
|
);
|
||||||
|
|
||||||
testWidgets('AppBar scrolledUnder does not trigger on horizontal scroll', (WidgetTester tester) async {
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
const Color scrolledColor = Color(0xff00ff00);
|
expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
|
||||||
const Color defaultColor = Color(0xff0000ff);
|
|
||||||
|
|
||||||
await tester.pumpWidget(
|
TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
||||||
MaterialApp(
|
await gesture.moveBy(const Offset(0.0, -expandedHeight));
|
||||||
home: Scaffold(
|
await gesture.up();
|
||||||
appBar: AppBar(
|
await tester.pumpAndSettle();
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: MaterialStateColor.resolveWith((Set<MaterialState> states) {
|
expect(getAppBarBackgroundColor(tester), scrolledColor);
|
||||||
return states.contains(MaterialState.scrolledUnder) ? scrolledColor : defaultColor;
|
expect(tester.getSize(findAppBarMaterial()).height, collapsedHeight);
|
||||||
}),
|
|
||||||
title: const Text('AppBar'),
|
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', (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),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
body: ListView(
|
);
|
||||||
scrollDirection: Axis.horizontal,
|
}
|
||||||
children: <Widget>[
|
|
||||||
Container(height: 600.0, width: 1200.0, 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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Finder findAppBarMaterial() {
|
expect(tester.takeException(), isNull);
|
||||||
return find.descendant(of: find.byType(AppBar), matching: find.byType(Material));
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Color? getAppBarBackgroundColor() {
|
testWidgets('does not trigger on horizontal scroll', (WidgetTester tester) async {
|
||||||
return tester.widget<Material>(findAppBarMaterial()).color;
|
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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
expect(getAppBarBackgroundColor(), defaultColor);
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
|
|
||||||
TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
TestGesture gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
||||||
await gesture.moveBy(const Offset(-100.0, 0.0));
|
await gesture.moveBy(const Offset(-100.0, 0.0));
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(getAppBarBackgroundColor(), defaultColor);
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
|
|
||||||
gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
gesture = await tester.startGesture(const Offset(50.0, 400.0));
|
||||||
await gesture.moveBy(const Offset(100.0, 0.0));
|
await gesture.moveBy(const Offset(100.0, 0.0));
|
||||||
await gesture.up();
|
await gesture.up();
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
expect(getAppBarBackgroundColor(), defaultColor);
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('backgroundColor - not triggered in reverse for short content', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
_buildAppBar(
|
||||||
|
contentHeight: 200.0,
|
||||||
|
reverse: true,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
|
expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||||
|
expect(tester.getSize(findAppBarMaterial()).height, kToolbarHeight);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async {
|
testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async {
|
||||||
|
@ -2302,9 +2302,9 @@ void main() {
|
|||||||
' PhysicalModel\n'
|
' PhysicalModel\n'
|
||||||
' AnimatedPhysicalModel\n'
|
' AnimatedPhysicalModel\n'
|
||||||
' Material\n'
|
' Material\n'
|
||||||
' _ScrollNotificationObserverScope\n'
|
' _ScrollMetricsNotificationObserverScope\n'
|
||||||
' NotificationListener<ScrollNotification>\n'
|
' NotificationListener<ScrollMetricsNotification>\n'
|
||||||
' ScrollNotificationObserver\n'
|
' ScrollMetricsNotificationObserver\n'
|
||||||
' _ScaffoldScope\n'
|
' _ScaffoldScope\n'
|
||||||
' Scaffold\n'
|
' Scaffold\n'
|
||||||
' MediaQuery\n'
|
' MediaQuery\n'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user