Commit 0d4b9970 authored by Eric Seidel's avatar Eric Seidel

Add a pageChanged callback to PageableList

Also includes changes to widget_tester sufficient to
test scrolling.

@abarth
parent 338ca571
...@@ -542,6 +542,8 @@ class ScrollableList<T> extends ScrollableWidgetList { ...@@ -542,6 +542,8 @@ class ScrollableList<T> extends ScrollableWidgetList {
} }
} }
typedef void PageChangedCallback(int newPage);
class PageableList<T> extends ScrollableList<T> { class PageableList<T> extends ScrollableList<T> {
PageableList({ PageableList({
Key key, Key key,
...@@ -551,6 +553,7 @@ class PageableList<T> extends ScrollableList<T> { ...@@ -551,6 +553,7 @@ class PageableList<T> extends ScrollableList<T> {
ItemBuilder<T> itemBuilder, ItemBuilder<T> itemBuilder,
bool itemsWrap: false, bool itemsWrap: false,
double itemExtent, double itemExtent,
PageChangedCallback this.pageChanged,
EdgeDims padding, EdgeDims padding,
this.duration: const Duration(milliseconds: 200), this.duration: const Duration(milliseconds: 200),
this.curve: ease this.curve: ease
...@@ -567,10 +570,12 @@ class PageableList<T> extends ScrollableList<T> { ...@@ -567,10 +570,12 @@ class PageableList<T> extends ScrollableList<T> {
Duration duration; Duration duration;
Curve curve; Curve curve;
PageChangedCallback pageChanged;
void syncConstructorArguments(PageableList<T> source) { void syncConstructorArguments(PageableList<T> source) {
duration = source.duration; duration = source.duration;
curve = source.curve; curve = source.curve;
pageChanged = source.pageChanged;
super.syncConstructorArguments(source); super.syncConstructorArguments(source);
} }
...@@ -592,12 +597,19 @@ class PageableList<T> extends ScrollableList<T> { ...@@ -592,12 +597,19 @@ class PageableList<T> extends ScrollableList<T> {
double newScrollOffset = _snapScrollOffset(scrollOffset + velocity.sign * itemExtent) double newScrollOffset = _snapScrollOffset(scrollOffset + velocity.sign * itemExtent)
.clamp(_snapScrollOffset(scrollOffset - itemExtent / 2.0), .clamp(_snapScrollOffset(scrollOffset - itemExtent / 2.0),
_snapScrollOffset(scrollOffset + itemExtent / 2.0)); _snapScrollOffset(scrollOffset + itemExtent / 2.0));
scrollTo(newScrollOffset, duration: duration, curve: curve); scrollTo(newScrollOffset, duration: duration, curve: curve).then(_notifyPageChanged);
return EventDisposition.processed; return EventDisposition.processed;
} }
int get currentPage => (scrollOffset / itemExtent).floor();
void _notifyPageChanged(_) {
if (pageChanged != null)
pageChanged(currentPage);
}
void settleScrollOffset() { void settleScrollOffset() {
scrollTo(_snapScrollOffset(scrollOffset), duration: duration, curve: curve); scrollTo(_snapScrollOffset(scrollOffset), duration: duration, curve: curve).then(_notifyPageChanged);
} }
} }
......
...@@ -3,6 +3,7 @@ dependencies: ...@@ -3,6 +3,7 @@ dependencies:
sky: any sky: any
sky_tools: any sky_tools: any
test: any test: any
quiver: any
dependency_overrides: dependency_overrides:
material_design_icons: material_design_icons:
path: ../packages/material_design_icons path: ../packages/material_design_icons
......
import 'package:sky/widgets.dart';
import 'package:test/test.dart';
import 'package:quiver/testing/async.dart';
import 'widget_tester.dart';
void main() {
test('Scrolling changes page', () {
WidgetTester tester = new WidgetTester();
List<int> pages = [0, 1, 2, 3, 4, 5];
Size pageSize = new Size(200.0, 200.0);
int currentPage;
Widget buildPage(int page) {
return new Container(
key: new StringKey(page.toString()),
width: pageSize.width,
height: pageSize.height,
child: new Text(page.toString())
);
}
Widget builder() {
return new Container(
height: pageSize.height,
child: new PageableList<int>(
padding: new EdgeDims.symmetric(horizontal: 10.0),
items: pages,
itemBuilder: buildPage,
scrollDirection: ScrollDirection.horizontal,
itemExtent: pageSize.width,
pageChanged: (int page) {
currentPage = page;
}
)
);
}
tester.pumpFrame(builder);
// TODO(abarth): We shouldn't need to pump a second frame here.
tester.pumpFrame(builder);
expect(currentPage, isNull);
new FakeAsync().run((async) {
tester.scroll(tester.findText('1'), new Offset(300.0, 0.0));
// One frame to start the animation, a second to complete it.
tester.pumpFrame(builder);
tester.pumpFrame(builder, 5000.0);
async.elapse(new Duration(seconds: 5));
expect(currentPage, equals(2));
});
});
}
import 'dart:sky' as sky; import 'dart:sky' as sky;
import 'package:sky/rendering.dart'; import 'package:sky/rendering.dart';
import 'package:sky/widgets.dart'; import 'package:sky/widgets.dart';
import 'package:sky/base/scheduler.dart' as scheduler;
typedef Widget WidgetBuilder(); typedef Widget WidgetBuilder();
...@@ -21,6 +22,63 @@ class TestApp extends App { ...@@ -21,6 +22,63 @@ class TestApp extends App {
} }
} }
class TestPointerEvent extends sky.PointerEvent {
TestPointerEvent({
this.type,
this.pointer,
this.kind,
this.x,
this.y,
this.dx,
this.dy,
this.velocityX,
this.velocityY,
this.buttons,
this.down,
this.primary,
this.obscured,
this.pressure,
this.pressureMin,
this.pressureMax,
this.distance,
this.distanceMin,
this.distanceMax,
this.radiusMajor,
this.radiusMinor,
this.radiusMin,
this.radiusMax,
this.orientation,
this.tilt
});
// These are all of the PointerEvent members, but not all of Event.
String type;
int pointer;
String kind;
double x;
double y;
double dx;
double dy;
double velocityX;
double velocityY;
int buttons;
bool down;
bool primary;
bool obscured;
double pressure;
double pressureMin;
double pressureMax;
double distance;
double distanceMin;
double distanceMax;
double radiusMajor;
double radiusMinor;
double radiusMin;
double radiusMax;
double orientation;
double tilt;
}
class TestGestureEvent extends sky.GestureEvent { class TestGestureEvent extends sky.GestureEvent {
TestGestureEvent({ TestGestureEvent({
this.type, this.type,
...@@ -33,6 +91,7 @@ class TestGestureEvent extends sky.GestureEvent { ...@@ -33,6 +91,7 @@ class TestGestureEvent extends sky.GestureEvent {
this.velocityY this.velocityY
}); });
// These are all of the GestureEvent members, but not all of Event.
String type; String type;
int primaryPointer; int primaryPointer;
double x; double x;
...@@ -105,14 +164,25 @@ class WidgetTester { ...@@ -105,14 +164,25 @@ class WidgetTester {
dispatchEvent(new TestGestureEvent(type: 'gesturetap'), getCenter(widget)); dispatchEvent(new TestGestureEvent(type: 'gesturetap'), getCenter(widget));
} }
void scroll(Widget widget, Offset offset) {
dispatchEvent(new TestGestureEvent(type: 'gesturescrollstart'), getCenter(widget));
dispatchEvent(new TestGestureEvent(
type: 'gesturescrollupdate',
dx: offset.dx,
dy: offset.dy), getCenter(widget));
// pointerup to trigger scroll settling in Scrollable<T>
dispatchEvent(new TestPointerEvent(
type: 'pointerup', down: false, primary: true), getCenter(widget));
}
void dispatchEvent(sky.Event event, Point position) { void dispatchEvent(sky.Event event, Point position) {
HitTestResult result = SkyBinding.instance.hitTest(position); HitTestResult result = SkyBinding.instance.hitTest(position);
SkyBinding.instance.dispatchEvent(event, result); SkyBinding.instance.dispatchEvent(event, result);
} }
void pumpFrame(WidgetBuilder builder) { void pumpFrame(WidgetBuilder builder, [double frameTimeMs = 0.0]) {
_app.builder = builder; _app.builder = builder;
SkyBinding.instance.beginFrame(0.0); scheduler.beginFrame(frameTimeMs);
} }
} }
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