Commit 7beedd7a authored by Hans Muller's avatar Hans Muller Committed by GitHub

Report ScrollNotification depth (#4992)

parent 6cc6c95b
......@@ -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.
......
// 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]));
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment