From b77990cc2ed0b009ba89a1d151f3f247c56b4053 Mon Sep 17 00:00:00 2001 From: Hans Muller Date: Wed, 30 Sep 2015 14:13:11 -0700 Subject: [PATCH] Snap scrolling: additional tests, cleanup --- examples/widgets/card_collection.dart | 59 ++++++------- sky/packages/sky/lib/src/fn3/scrollable.dart | 3 +- sky/unit/test/widget/snap_scrolling_test.dart | 84 ++++++++++++++----- 3 files changed, 95 insertions(+), 51 deletions(-) diff --git a/examples/widgets/card_collection.dart b/examples/widgets/card_collection.dart index 9dbeca792ea52..bb84246435254 100644 --- a/examples/widgets/card_collection.dart +++ b/examples/widgets/card_collection.dart @@ -70,6 +70,36 @@ class CardCollectionAppState extends State { _initCardModels(); } + double _variableSizeToSnapOffset(double scrollOffset) { + double cumulativeHeight = 0.0; + double margins = 8.0; + List cumulativeHeights = _cardModels.map((card) { + cumulativeHeight += card.height + margins; + return cumulativeHeight; + }) + .toList(); + + double offsetForIndex(int i) { + return 12.0 + (margins + _cardModels[i].height) / 2.0 + ((i == 0) ? 0.0 : cumulativeHeights[i - 1]); + } + + for (int i = 0; i < cumulativeHeights.length; i++) { + if (cumulativeHeights[i] >= scrollOffset) + return offsetForIndex(i); + } + return offsetForIndex(cumulativeHeights.length - 1); + } + + double _fixedSizeToSnapOffset(double scrollOffset) { + double cardHeight = _cardModels[0].height; + int cardIndex = (scrollOffset.clamp(0.0, cardHeight * (_cardModels.length - 1)) / cardHeight).floor(); + return 12.0 + cardIndex * cardHeight + cardHeight * 0.5; + } + + double _toSnapOffset(double scrollOffset) { + return _fixedSizeCards ? _fixedSizeToSnapOffset(scrollOffset) : _variableSizeToSnapOffset(scrollOffset); + } + void dismissCard(CardModel card) { if (_cardModels.contains(card)) { setState(() { @@ -155,7 +185,7 @@ class CardCollectionAppState extends State { new DrawerHeader(child: new Text('Options')), buildDrawerCheckbox("Snap fling scrolls to center", _snapToCenter, _toggleSnapToCenter), buildDrawerCheckbox("Fixed size cards", _fixedSizeCards, _toggleFixedSizeCards), - new DrawerDivider(),//buildDrawerSpacerItem(), + new DrawerDivider(), buildDrawerRadioItem(DismissDirection.horizontal, 'action/code'), buildDrawerRadioItem(DismissDirection.left, 'navigation/arrow_back'), buildDrawerRadioItem(DismissDirection.right, 'navigation/arrow_forward'), @@ -255,33 +285,6 @@ class CardCollectionAppState extends State { }); } - double _variableSizeToSnapOffset(double scrollOffset) { - double cumulativeHeight = 0.0; - double margins = 8.0; - List cumulativeHeights = _cardModels.map((card) { - cumulativeHeight += card.height + margins; - return cumulativeHeight; - }) - .toList(); - - for (int i = 0; i < cumulativeHeights.length; i++) { - if (cumulativeHeights[i] >= scrollOffset) - return 12.0 + (margins + _cardModels[i].height) / 2.0 + ((i == 0) ? 0.0 : cumulativeHeights[i - 1]); - } - - assert(false); - return 0.0; - } - - double _fixedSizeToSnapOffset(double scrollOffset) { - double cardHeight = _cardModels[0].height; - return 12.0 + (scrollOffset / cardHeight).floor() * cardHeight + cardHeight * 0.5; - } - - double _toSnapOffset(double scrollOffset) { - return _fixedSizeCards ? _fixedSizeToSnapOffset(scrollOffset) : _variableSizeToSnapOffset(scrollOffset); - } - Widget build(BuildContext context) { Widget cardCollection; diff --git a/sky/packages/sky/lib/src/fn3/scrollable.dart b/sky/packages/sky/lib/src/fn3/scrollable.dart index 4e9dd3c2426cd..d5959beac3d21 100644 --- a/sky/packages/sky/lib/src/fn3/scrollable.dart +++ b/sky/packages/sky/lib/src/fn3/scrollable.dart @@ -147,8 +147,9 @@ abstract class ScrollableState extends State { if (!endScrollOffset.isNaN) { double alignedScrollOffset = _alignedScrollSnapOffset(endScrollOffset); if (_scrollOffsetIsInBounds(alignedScrollOffset)) { + double snapVelocity = velocity.abs() * (alignedScrollOffset - scrollOffset).sign; Simulation toSnapSimulation = scrollBehavior.createSnapScrollSimulation( - scrollOffset, alignedScrollOffset, velocity); + scrollOffset, alignedScrollOffset, snapVelocity); _toEndAnimation.start(toSnapSimulation); return; } diff --git a/sky/unit/test/widget/snap_scrolling_test.dart b/sky/unit/test/widget/snap_scrolling_test.dart index 8a99d46ad68ba..185d1077a468c 100644 --- a/sky/unit/test/widget/snap_scrolling_test.dart +++ b/sky/unit/test/widget/snap_scrolling_test.dart @@ -25,17 +25,19 @@ double snapOffsetCallback(double offset) { return (offset / itemExtent).floor() * itemExtent; } -Widget buildScrollableList() { +Widget buildFrame() { scrollableListKey = new GlobalKey(); - return new Container( - height: itemExtent * 2.0, - child: new ScrollableList( - key: scrollableListKey, - snapOffsetCallback: snapOffsetCallback, - scrollDirection: scrollDirection, - items: [0, 1, 2, 3, 4, 5, 7, 8, 9], - itemBuilder: buildItem, - itemExtent: itemExtent + return new Center( + child: new Container( + height: itemExtent * 2.0, + child: new ScrollableList( + key: scrollableListKey, + snapOffsetCallback: snapOffsetCallback, + scrollDirection: scrollDirection, + items: [0, 1, 2, 3, 4, 5, 7, 8, 9], + itemBuilder: buildItem, + itemExtent: itemExtent + ) ) ); } @@ -55,33 +57,71 @@ void fling(double velocity) { } void main() { - test('ScrollableList snap scrolling, fling(-800)', () { - WidgetTester tester = new WidgetTester(); + WidgetTester tester = new WidgetTester(); + tester.pumpFrame(buildFrame()); - tester.pumpFrame(new Center(child: buildScrollableList())); + test('ScrollableList snap scrolling, fling(-800)', () { + scrollOffset = 0.0; + tester.pumpFrameWithoutChange(); expect(scrollOffset, 0.0); + double t0 = 0.0; + int dt = 1000; new FakeAsync().run((async) { fling(-800.0); - tester.pumpFrameWithoutChange(); // Start the scheduler at 0.0 - tester.pumpFrameWithoutChange(1000.0); - async.elapse(new Duration(seconds: 1)); + tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0 + tester.pumpFrameWithoutChange(t0 + dt); + async.elapse(new Duration(milliseconds: dt)); expect(scrollOffset, closeTo(200.0, 1.0)); }); }); test('ScrollableList snap scrolling, fling(-2000)', () { - WidgetTester tester = new WidgetTester(); - - tester.pumpFrame(new Center(child: buildScrollableList())); + scrollOffset = 0.0; + tester.pumpFrameWithoutChange(); expect(scrollOffset, 0.0); + double t0 = 0.0; + int dt = 1000; new FakeAsync().run((async) { fling(-2000.0); - tester.pumpFrameWithoutChange(); // Start the scheduler at 0.0 - tester.pumpFrameWithoutChange(1000.0); - async.elapse(new Duration(seconds: 1)); + tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0 + tester.pumpFrameWithoutChange(t0 + dt); + async.elapse(new Duration(milliseconds: dt)); expect(scrollOffset, closeTo(400.0, 1.0)); }); }); + + test('ScrollableList snap scrolling, fling(800)', () { + scrollOffset = 400.0; + tester.pumpFrameWithoutChange(1000.0); + expect(scrollOffset, 400.0); + + double t0 = 0.0; + int dt = 2000; + new FakeAsync().run((async) { + fling(800.0); + tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0 + tester.pumpFrameWithoutChange(t0 + dt); + async.elapse(new Duration(milliseconds: dt)); + expect(scrollOffset, closeTo(0.0, 1.0)); + }); + }); + + test('ScrollableList snap scrolling, fling(2000)', () { + scrollOffset = 800.0; + tester.pumpFrameWithoutChange(1000.0); + expect(scrollOffset, 800.0); + + double t0 = 0.0; + int dt = 1500; + new FakeAsync().run((async) { + fling(2000.0); + tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0 + tester.pumpFrameWithoutChange(t0 + dt); + async.elapse(new Duration(milliseconds: dt)); + expect(scrollOffset, closeTo(200.0, 1.0)); + }); + }); + }