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 {
}
}
typedef void PageChangedCallback(int newPage);
class PageableList<T> extends ScrollableList<T> {
PageableList({
Key key,
......@@ -551,6 +553,7 @@ class PageableList<T> extends ScrollableList<T> {
ItemBuilder<T> itemBuilder,
bool itemsWrap: false,
double itemExtent,
PageChangedCallback this.pageChanged,
EdgeDims padding,
this.duration: const Duration(milliseconds: 200),
this.curve: ease
......@@ -567,10 +570,12 @@ class PageableList<T> extends ScrollableList<T> {
Duration duration;
Curve curve;
PageChangedCallback pageChanged;
void syncConstructorArguments(PageableList<T> source) {
duration = source.duration;
curve = source.curve;
pageChanged = source.pageChanged;
super.syncConstructorArguments(source);
}
......@@ -592,12 +597,19 @@ class PageableList<T> extends ScrollableList<T> {
double newScrollOffset = _snapScrollOffset(scrollOffset + velocity.sign * itemExtent)
.clamp(_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;
}
int get currentPage => (scrollOffset / itemExtent).floor();
void _notifyPageChanged(_) {
if (pageChanged != null)
pageChanged(currentPage);
}
void settleScrollOffset() {
scrollTo(_snapScrollOffset(scrollOffset), duration: duration, curve: curve);
scrollTo(_snapScrollOffset(scrollOffset), duration: duration, curve: curve).then(_notifyPageChanged);
}
}
......
......@@ -3,6 +3,7 @@ dependencies:
sky: any
sky_tools: any
test: any
quiver: any
dependency_overrides:
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 'package:sky/rendering.dart';
import 'package:sky/widgets.dart';
import 'package:sky/base/scheduler.dart' as scheduler;
typedef Widget WidgetBuilder();
......@@ -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 {
TestGestureEvent({
this.type,
......@@ -33,6 +91,7 @@ class TestGestureEvent extends sky.GestureEvent {
this.velocityY
});
// These are all of the GestureEvent members, but not all of Event.
String type;
int primaryPointer;
double x;
......@@ -105,14 +164,25 @@ class WidgetTester {
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) {
HitTestResult result = SkyBinding.instance.hitTest(position);
SkyBinding.instance.dispatchEvent(event, result);
}
void pumpFrame(WidgetBuilder builder) {
void pumpFrame(WidgetBuilder builder, [double frameTimeMs = 0.0]) {
_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