Commit d7576946 authored by Hans Muller's avatar Hans Muller

Merge pull request #1415 from HansMuller/snap_scrolling_tests

Snap scrolling: additional tests, cleanup
parents 1d0573fd 4ac05235
...@@ -70,6 +70,36 @@ class CardCollectionAppState extends State<CardCollectionApp> { ...@@ -70,6 +70,36 @@ class CardCollectionAppState extends State<CardCollectionApp> {
_initCardModels(); _initCardModels();
} }
double _variableSizeToSnapOffset(double scrollOffset) {
double cumulativeHeight = 0.0;
double margins = 8.0;
List<double> 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) { void dismissCard(CardModel card) {
if (_cardModels.contains(card)) { if (_cardModels.contains(card)) {
setState(() { setState(() {
...@@ -155,7 +185,7 @@ class CardCollectionAppState extends State<CardCollectionApp> { ...@@ -155,7 +185,7 @@ class CardCollectionAppState extends State<CardCollectionApp> {
new DrawerHeader(child: new Text('Options')), new DrawerHeader(child: new Text('Options')),
buildDrawerCheckbox("Snap fling scrolls to center", _snapToCenter, _toggleSnapToCenter), buildDrawerCheckbox("Snap fling scrolls to center", _snapToCenter, _toggleSnapToCenter),
buildDrawerCheckbox("Fixed size cards", _fixedSizeCards, _toggleFixedSizeCards), buildDrawerCheckbox("Fixed size cards", _fixedSizeCards, _toggleFixedSizeCards),
new DrawerDivider(),//buildDrawerSpacerItem(), new DrawerDivider(),
buildDrawerRadioItem(DismissDirection.horizontal, 'action/code'), buildDrawerRadioItem(DismissDirection.horizontal, 'action/code'),
buildDrawerRadioItem(DismissDirection.left, 'navigation/arrow_back'), buildDrawerRadioItem(DismissDirection.left, 'navigation/arrow_back'),
buildDrawerRadioItem(DismissDirection.right, 'navigation/arrow_forward'), buildDrawerRadioItem(DismissDirection.right, 'navigation/arrow_forward'),
...@@ -255,33 +285,6 @@ class CardCollectionAppState extends State<CardCollectionApp> { ...@@ -255,33 +285,6 @@ class CardCollectionAppState extends State<CardCollectionApp> {
}); });
} }
double _variableSizeToSnapOffset(double scrollOffset) {
double cumulativeHeight = 0.0;
double margins = 8.0;
List<double> 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 build(BuildContext context) {
Widget cardCollection; Widget cardCollection;
......
...@@ -147,8 +147,9 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -147,8 +147,9 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
if (!endScrollOffset.isNaN) { if (!endScrollOffset.isNaN) {
double alignedScrollOffset = _alignedScrollSnapOffset(endScrollOffset); double alignedScrollOffset = _alignedScrollSnapOffset(endScrollOffset);
if (_scrollOffsetIsInBounds(alignedScrollOffset)) { if (_scrollOffsetIsInBounds(alignedScrollOffset)) {
double snapVelocity = velocity.abs() * (alignedScrollOffset - scrollOffset).sign;
Simulation toSnapSimulation = scrollBehavior.createSnapScrollSimulation( Simulation toSnapSimulation = scrollBehavior.createSnapScrollSimulation(
scrollOffset, alignedScrollOffset, velocity); scrollOffset, alignedScrollOffset, snapVelocity);
_toEndAnimation.start(toSnapSimulation); _toEndAnimation.start(toSnapSimulation);
return; return;
} }
......
...@@ -25,17 +25,19 @@ double snapOffsetCallback(double offset) { ...@@ -25,17 +25,19 @@ double snapOffsetCallback(double offset) {
return (offset / itemExtent).floor() * itemExtent; return (offset / itemExtent).floor() * itemExtent;
} }
Widget buildScrollableList() { Widget buildFrame() {
scrollableListKey = new GlobalKey(); scrollableListKey = new GlobalKey();
return new Container( return new Center(
height: itemExtent * 2.0, child: new Container(
child: new ScrollableList<int>( height: itemExtent * 2.0,
key: scrollableListKey, child: new ScrollableList<int>(
snapOffsetCallback: snapOffsetCallback, key: scrollableListKey,
scrollDirection: scrollDirection, snapOffsetCallback: snapOffsetCallback,
items: [0, 1, 2, 3, 4, 5, 7, 8, 9], scrollDirection: scrollDirection,
itemBuilder: buildItem, items: [0, 1, 2, 3, 4, 5, 7, 8, 9],
itemExtent: itemExtent itemBuilder: buildItem,
itemExtent: itemExtent
)
) )
); );
} }
...@@ -55,33 +57,71 @@ void fling(double velocity) { ...@@ -55,33 +57,71 @@ void fling(double velocity) {
} }
void main() { 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); expect(scrollOffset, 0.0);
double t0 = 0.0;
int dt = 1000;
new FakeAsync().run((async) { new FakeAsync().run((async) {
fling(-800.0); fling(-800.0);
tester.pumpFrameWithoutChange(); // Start the scheduler at 0.0 tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0
tester.pumpFrameWithoutChange(1000.0); tester.pumpFrameWithoutChange(t0 + dt);
async.elapse(new Duration(seconds: 1)); async.elapse(new Duration(milliseconds: dt));
expect(scrollOffset, closeTo(200.0, 1.0)); expect(scrollOffset, closeTo(200.0, 1.0));
}); });
}); });
test('ScrollableList snap scrolling, fling(-2000)', () { test('ScrollableList snap scrolling, fling(-2000)', () {
WidgetTester tester = new WidgetTester(); scrollOffset = 0.0;
tester.pumpFrameWithoutChange();
tester.pumpFrame(new Center(child: buildScrollableList()));
expect(scrollOffset, 0.0); expect(scrollOffset, 0.0);
double t0 = 0.0;
int dt = 1000;
new FakeAsync().run((async) { new FakeAsync().run((async) {
fling(-2000.0); fling(-2000.0);
tester.pumpFrameWithoutChange(); // Start the scheduler at 0.0 tester.pumpFrameWithoutChange(t0); // Start the scheduler at 0.0
tester.pumpFrameWithoutChange(1000.0); tester.pumpFrameWithoutChange(t0 + dt);
async.elapse(new Duration(seconds: 1)); async.elapse(new Duration(milliseconds: dt));
expect(scrollOffset, closeTo(400.0, 1.0)); 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));
});
});
} }
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