mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Re-land reverse case for AppBar scrolled under (#102343)
This commit is contained in:
parent
3bd19f2297
commit
558016455a
@ -767,17 +767,33 @@ class _AppBarState extends State<AppBar> {
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (_scrolledUnder != oldScrolledUnder) {
|
||||
setState(() {
|
||||
// React to a change in MaterialState.scrolledUnder
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Color _resolveColor(Set<MaterialState> states, Color? widgetColor, Color? themeColor, Color defaultColor) {
|
||||
|
||||
@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'framework.dart';
|
||||
import 'notification_listener.dart';
|
||||
import 'scroll_notification.dart';
|
||||
import 'scroll_position.dart';
|
||||
|
||||
/// A [ScrollNotification] listener for [ScrollNotificationObserver].
|
||||
///
|
||||
@ -151,14 +152,26 @@ class ScrollNotificationObserverState extends State<ScrollNotificationObserver>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification notification) {
|
||||
_notifyListeners(notification);
|
||||
// A ScrollMetricsNotification allows listeners to be notified for an
|
||||
// initial state, as well as if the content dimensions change without
|
||||
// scrolling.
|
||||
return NotificationListener<ScrollMetricsNotification>(
|
||||
onNotification: (ScrollMetricsNotification notification) {
|
||||
_notifyListeners(_ConvertedScrollMetricsNotification(
|
||||
metrics: notification.metrics,
|
||||
context: notification.context,
|
||||
));
|
||||
return false;
|
||||
},
|
||||
child: _ScrollNotificationObserverScope(
|
||||
scrollNotificationObserverState: this,
|
||||
child: widget.child,
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification notification) {
|
||||
_notifyListeners(notification);
|
||||
return false;
|
||||
},
|
||||
child: _ScrollNotificationObserverScope(
|
||||
scrollNotificationObserverState: this,
|
||||
child: widget.child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -170,3 +183,10 @@ class ScrollNotificationObserverState extends State<ScrollNotificationObserver>
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class _ConvertedScrollMetricsNotification extends ScrollNotification {
|
||||
_ConvertedScrollMetricsNotification({
|
||||
required super.metrics,
|
||||
required super.context,
|
||||
});
|
||||
}
|
||||
|
||||
@ -2567,311 +2567,457 @@ void main() {
|
||||
expect(actionIconTheme.color, foregroundColor);
|
||||
});
|
||||
|
||||
testWidgets('SliverAppBar.backgroundColor MaterialStateColor scrolledUnder', (WidgetTester tester) async {
|
||||
group('MaterialStateColor scrolledUnder', () {
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Color? getAppBarBackgroundColor() {
|
||||
Color? getAppBarBackgroundColor(WidgetTester tester) {
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
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),
|
||||
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(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 {
|
||||
const Color scrolledColor = Color(0xff00ff00);
|
||||
const Color defaultColor = Color(0xff0000ff);
|
||||
expect(getAppBarBackgroundColor(tester), defaultColor);
|
||||
expect(tester.getSize(findAppBarMaterial()).height, expandedHeight);
|
||||
|
||||
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'),
|
||||
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', (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('_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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
Finder findAppBarMaterial() {
|
||||
return find.descendant(of: find.byType(AppBar), matching: find.byType(Material));
|
||||
}
|
||||
expect(tester.takeException(), isNull);
|
||||
});
|
||||
|
||||
Color? getAppBarBackgroundColor() {
|
||||
return tester.widget<Material>(findAppBarMaterial()).color;
|
||||
}
|
||||
testWidgets('does not trigger on horizontal scroll', (WidgetTester tester) async {
|
||||
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));
|
||||
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(-100.0, 0.0));
|
||||
await gesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(getAppBarBackgroundColor(), defaultColor);
|
||||
expect(getAppBarBackgroundColor(tester), 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();
|
||||
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);
|
||||
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 {
|
||||
|
||||
@ -349,6 +349,7 @@ void main() {
|
||||
' Material\n'
|
||||
' _ScrollNotificationObserverScope\n'
|
||||
' NotificationListener<ScrollNotification>\n'
|
||||
' NotificationListener<ScrollMetricsNotification>\n'
|
||||
' ScrollNotificationObserver\n'
|
||||
' _ScaffoldScope\n'
|
||||
' Scaffold-[LabeledGlobalKey<ScaffoldState>#00000]\n'
|
||||
|
||||
@ -2339,6 +2339,7 @@ void main() {
|
||||
' Material\n'
|
||||
' _ScrollNotificationObserverScope\n'
|
||||
' NotificationListener<ScrollNotification>\n'
|
||||
' NotificationListener<ScrollMetricsNotification>\n'
|
||||
' ScrollNotificationObserver\n'
|
||||
' _ScaffoldScope\n'
|
||||
' Scaffold\n'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user