Merge pull request #1415 from HansMuller/snap_scrolling_tests
Snap scrolling: additional tests, cleanup
This commit is contained in:
commit
d757694618
@ -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> {
|
|||||||
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> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
|||||||
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,9 +25,10 @@ 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(
|
||||||
|
child: new Container(
|
||||||
height: itemExtent * 2.0,
|
height: itemExtent * 2.0,
|
||||||
child: new ScrollableList<int>(
|
child: new ScrollableList<int>(
|
||||||
key: scrollableListKey,
|
key: scrollableListKey,
|
||||||
@ -37,6 +38,7 @@ Widget buildScrollableList() {
|
|||||||
itemBuilder: buildItem,
|
itemBuilder: buildItem,
|
||||||
itemExtent: itemExtent
|
itemExtent: itemExtent
|
||||||
)
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user