Fix scrolling in the Drawer and NavigationDrawer triggers AppBar's scrolledUnderElevation (#122600)

Fix scrolling in the  `Drawer` and `NavigationDrawer` triggers AppBar's scrolledUnderElevation
This commit is contained in:
Taha Tesser 2023-03-30 02:02:11 +03:00 committed by GitHub
parent 32b75f08fe
commit 6e04bddd86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 100 additions and 1 deletions

View file

@ -763,7 +763,8 @@ class _AppBarState extends State<AppBar> {
}
void _handleScrollNotification(ScrollNotification notification) {
if (notification is ScrollUpdateNotification && widget.notificationPredicate(notification)) {
if (notification is ScrollUpdateNotification && widget.notificationPredicate(notification)
&& Scaffold.isBodyDescendant(notification.context!)) {
final bool oldScrolledUnder = _scrolledUnder;
final ScrollMetrics metrics = notification.metrics;
switch (metrics.axisDirection) {

View file

@ -1994,6 +1994,17 @@ class Scaffold extends StatefulWidget {
}
}
/// Whether the given context is descendant of the [Scaffold.body].
///
/// This is used by [AppBar] to determine if the [AppBar] should listen to
/// [ScrollNotification] from the [Scrollable]s in the [Scaffold.body].
///
/// It returns true if the given context is descendant of the [Scaffold.body].
static bool isBodyDescendant(BuildContext context) {
final _BodyBuilder? body = context.findAncestorWidgetOfExactType<_BodyBuilder>();
return body != null;
}
@override
ScaffoldState createState() => ScaffoldState();
}

View file

@ -4501,4 +4501,75 @@ void main() {
expect(buttonWasPressed, isFalse);
});
});
testWidgets("scrolledUnderElevation only listens to scroll notifications from Scaffold's body", (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
Widget buildWidget() {
return MaterialApp(
theme: ThemeData(useMaterial3: true),
home: Scaffold(
key: scaffoldKey,
appBar: AppBar(),
drawer: Drawer(
child: ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('$index'),
);
}
),
),
body: ListView.builder(
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text('$index'),
);
}
),
),
);
}
await tester.pumpWidget(buildWidget());
// The first Material is the AppBar's Material.
Material getMaterial() => tester.widget<Material>(find.descendant(
of: find.byType(AppBar),
matching: find.byType(Material),
).first);
expect(getMaterial().elevation, 0.0);
// Scroll down the list view in the body.
await tester.drag(find.byType(ListView), const Offset(0.0, -300.0));
await tester.pumpAndSettle();
// AppBar should be elevated.
expect(getMaterial().elevation, 3.0);
// Scroll up the list view in the body.
await tester.drag(find.byType(ListView), const Offset(0.0, 300.0));
await tester.pumpAndSettle();
// AppBar should not be elevated.
expect(getMaterial().elevation, 0.0);
final ScaffoldState state = tester.firstState(find.byType(Scaffold));
// Open the drawer.
state.openDrawer();
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(scaffoldKey.currentState!.isDrawerOpen, isTrue);
// Scroll down the list view in the drawer.
await tester.drag(find.byType(ListView).last, const Offset(0.0, -250.0));
await tester.pump();
// AppBar should still not be elevated.
expect(getMaterial().elevation, 0.0);
});
}

View file

@ -2698,6 +2698,22 @@ void main() {
expect(tester.takeException(), isNull);
});
testWidgets('Scaffold.isBodyDescendant checks if given context is descendant of the body', (WidgetTester tester) async {
final GlobalKey scaffoldKey = GlobalKey();
final GlobalKey bodyChildKey = GlobalKey();
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
key: scaffoldKey,
body: SizedBox(key: bodyChildKey),
),
),
);
expect(Scaffold.isBodyDescendant(scaffoldKey.currentContext!), false);
expect(Scaffold.isBodyDescendant(bodyChildKey.currentContext!), true);
});
}
class _GeometryListener extends StatefulWidget {