Report ScrollNotification depth (#4992)
This commit is contained in:
parent
6cc6c95b79
commit
7beedd7a95
@ -188,6 +188,8 @@ class _OverscrollIndicatorState extends State<OverscrollIndicator> {
|
||||
}
|
||||
|
||||
bool _handleScrollNotification(ScrollNotification notification) {
|
||||
if (notification.depth != 0)
|
||||
return false;
|
||||
if (config.scrollableKey == null || config.scrollableKey == notification.scrollable.config.key) {
|
||||
final ScrollableState scrollable = notification.scrollable;
|
||||
switch(notification.kind) {
|
||||
|
@ -9,18 +9,22 @@ typedef bool NotificationListenerCallback<T extends Notification>(T notification
|
||||
|
||||
/// A notification that can bubble up the widget tree.
|
||||
abstract class Notification {
|
||||
/// Applied to each ancestor of the [dispatch] target. Dispatches this
|
||||
/// Notification to ancestor [NotificationListener] widgets.
|
||||
bool visitAncestor(Element element) {
|
||||
if (element is StatelessElement &&
|
||||
element.widget is NotificationListener<Notification>) {
|
||||
final NotificationListener<Notification> widget = element.widget;
|
||||
if (widget._dispatch(this)) // that function checks the type dynamically
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Start bubbling this notification at the given build context.
|
||||
void dispatch(BuildContext target) {
|
||||
assert(target != null); // Only call dispatch if the widget's State is still mounted.
|
||||
target.visitAncestorElements((Element element) {
|
||||
if (element is StatelessElement &&
|
||||
element.widget is NotificationListener<Notification>) {
|
||||
final NotificationListener<Notification> widget = element.widget;
|
||||
if (widget._dispatch(this)) // that function checks the type dynamically
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
target.visitAncestorElements(visitAncestor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,11 @@ enum ScrollNotificationKind {
|
||||
ended
|
||||
}
|
||||
|
||||
/// Indicates that a descendant scrollable has scrolled.
|
||||
/// Indicates that a scrollable descendant is scrolling.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [NotificationListener]
|
||||
class ScrollNotification extends Notification {
|
||||
/// Creates a notification about scrolling.
|
||||
ScrollNotification(this.scrollable, this.kind);
|
||||
@ -720,6 +724,19 @@ class ScrollNotification extends Notification {
|
||||
|
||||
/// The scrollable that scrolled.
|
||||
final ScrollableState scrollable;
|
||||
|
||||
/// The number of scrollable widgets that have already received this
|
||||
/// notification. Typically listeners only respond to notifications
|
||||
/// with depth = 0.
|
||||
int get depth => _depth;
|
||||
int _depth = 0;
|
||||
|
||||
@override
|
||||
bool visitAncestor(Element element) {
|
||||
if (element is StatefulElement && element.state is ScrollableState)
|
||||
_depth += 1;
|
||||
return super.visitAncestor(element);
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple scrolling widget that has a single child.
|
||||
|
86
packages/flutter/test/widget/scroll_notification_test.dart
Normal file
86
packages/flutter/test/widget/scroll_notification_test.dart
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Scroll notifcation basics', (WidgetTester tester) async {
|
||||
ScrollNotification notification;
|
||||
|
||||
await tester.pumpWidget(new NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification value) {
|
||||
notification = value;
|
||||
return false;
|
||||
},
|
||||
child: new ScrollableViewport(
|
||||
child: new SizedBox(height: 1200.0)
|
||||
)
|
||||
));
|
||||
|
||||
TestGesture gesture = await tester.startGesture(new Point(100.0, 100.0));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect(notification.kind, equals(ScrollNotificationKind.started));
|
||||
expect(notification.depth, equals(0));
|
||||
|
||||
await gesture.moveBy(new Offset(-10.0, -10.0));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect(notification.kind, equals(ScrollNotificationKind.updated));
|
||||
expect(notification.depth, equals(0));
|
||||
|
||||
await gesture.up();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
expect(notification.kind, equals(ScrollNotificationKind.ended));
|
||||
expect(notification.depth, equals(0));
|
||||
});
|
||||
|
||||
testWidgets('Scroll notifcation depth', (WidgetTester tester) async {
|
||||
final List<ScrollNotificationKind> depth0Kinds = <ScrollNotificationKind>[];
|
||||
final List<ScrollNotificationKind> depth1Kinds = <ScrollNotificationKind>[];
|
||||
final List<int> depth0Values = <int>[];
|
||||
final List<int> depth1Values = <int>[];
|
||||
|
||||
await tester.pumpWidget(new NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification value) {
|
||||
depth1Kinds.add(value.kind);
|
||||
depth1Values.add(value.depth);
|
||||
return false;
|
||||
},
|
||||
child: new ScrollableViewport(
|
||||
child: new SizedBox(
|
||||
height: 1200.0,
|
||||
child: new NotificationListener<ScrollNotification>(
|
||||
onNotification: (ScrollNotification value) {
|
||||
depth0Kinds.add(value.kind);
|
||||
depth0Values.add(value.depth);
|
||||
return false;
|
||||
},
|
||||
child: new Container(
|
||||
padding: const EdgeInsets.all(50.0),
|
||||
child: new ScrollableViewport(child: new SizedBox(height: 1200.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
TestGesture gesture = await tester.startGesture(new Point(100.0, 100.0));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
await gesture.moveBy(new Offset(-10.0, -10.0));
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
await gesture.up();
|
||||
await tester.pump(const Duration(seconds: 1));
|
||||
|
||||
final List<ScrollNotificationKind> kinds = <ScrollNotificationKind>[
|
||||
ScrollNotificationKind.started,
|
||||
ScrollNotificationKind.updated,
|
||||
ScrollNotificationKind.ended
|
||||
];
|
||||
expect(depth0Kinds, equals(kinds));
|
||||
expect(depth1Kinds, equals(kinds));
|
||||
|
||||
expect(depth0Values, equals(<int>[0, 0, 0]));
|
||||
expect(depth1Values, equals(<int>[1, 1, 1]));
|
||||
});
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user