Commit c1d42a2f authored by Hans Muller's avatar Hans Muller

Revised PageableList

parent 4f22f3ec
......@@ -120,18 +120,11 @@ class PageableListAppState extends State<PageableListApp> {
}
Widget _buildBody(BuildContext context) {
Widget list = new PageableList<CardModel>(
return new PageableList<CardModel>(
items: cardModels,
itemsWrap: itemsWrap,
itemBuilder: buildCard,
scrollDirection: scrollDirection,
itemExtent: (scrollDirection == ScrollDirection.vertical)
? pageSize.height
: pageSize.width
);
return new SizeObserver(
onSizeChanged: updatePageSize,
child: list
scrollDirection: scrollDirection
);
}
......
......@@ -3,20 +3,13 @@
// found in the LICENSE file.
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:newton/newton.dart';
const double _kSecondsPerMillisecond = 1000.0;
const double _kScrollDrag = 0.025;
// TODO(abarth): These values won't work well if there's a scale transform.
final Tolerance _kDefaultScrollTolerance = new Tolerance(
velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
distance: 1.0 / ui.window.devicePixelRatio // logical pixels
);
/// An interface for controlling the behavior of scrollable widgets
/// An interface for controlling the behavior of scrollable widgets.
abstract class ScrollBehavior {
/// Called when a drag gesture ends. Returns a simulation that
/// propels the scrollOffset.
......@@ -24,10 +17,10 @@ abstract class ScrollBehavior {
/// Called when a drag gesture ends and toSnapOffset is specified.
/// Returns an animation that ends at the snap offset.
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double velocity) => null;
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double startVelocity, double endVelocity) => null;
/// Return the scroll offset to use when the user attempts to scroll
/// from the given offset by the given delta
/// from the given offset by the given delta.
double applyCurve(double scrollOffset, double scrollDelta);
/// Whether this scroll behavior currently permits scrolling
......@@ -39,11 +32,11 @@ abstract class ExtentScrollBehavior extends ScrollBehavior {
ExtentScrollBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 })
: _contentExtent = contentExtent, _containerExtent = containerExtent;
/// The linear extent of the content inside the scrollable widget
/// The linear extent of the content inside the scrollable widget.
double get contentExtent => _contentExtent;
double _contentExtent;
/// The linear extent of the exterior of the scrollable widget
/// The linear extent of the exterior of the scrollable widget.
double get containerExtent => _containerExtent;
double _containerExtent;
......@@ -64,14 +57,14 @@ abstract class ExtentScrollBehavior extends ScrollBehavior {
return scrollOffset.clamp(minScrollOffset, maxScrollOffset);
}
/// The minimum value the scroll offset can obtain
/// The minimum value the scroll offset can obtain.
double get minScrollOffset;
/// The maximum value the scroll offset can obatin
/// The maximum value the scroll offset can obtain.
double get maxScrollOffset;
}
/// A scroll behavior that prevents the user from exeeding scroll bounds
/// A scroll behavior that prevents the user from exeeding scroll bounds.
class BoundedBehavior extends ExtentScrollBehavior {
BoundedBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 })
: super(contentExtent: contentExtent, containerExtent: containerExtent);
......@@ -84,7 +77,18 @@ class BoundedBehavior extends ExtentScrollBehavior {
}
}
/// A scroll behavior that does not prevent the user from exeeding scroll bounds
Simulation _createFlingScrollSimulation(double position, double velocity, double minScrollOffset, double maxScrollOffset) {
final double startVelocity = velocity * _kSecondsPerMillisecond;
final SpringDescription spring = new SpringDescription.withDampingRatio(mass: 1.0, springConstant: 170.0, ratio: 1.1);
return new ScrollSimulation(position, startVelocity, minScrollOffset, maxScrollOffset, spring, _kScrollDrag);
}
Simulation _createSnapScrollSimulation(double startOffset, double endOffset, double startVelocity, double endVelocity) {
final double velocity = startVelocity * _kSecondsPerMillisecond;
return new FrictionSimulation.through(startOffset, endOffset, velocity, endVelocity);
}
/// A scroll behavior that does not prevent the user from exeeding scroll bounds.
class UnboundedBehavior extends ExtentScrollBehavior {
UnboundedBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 })
: super(contentExtent: contentExtent, containerExtent: containerExtent);
......@@ -96,8 +100,8 @@ class UnboundedBehavior extends ExtentScrollBehavior {
);
}
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double velocity) {
return _createSnapScrollSimulation(startOffset, endOffset, velocity);
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double startVelocity, double endVelocity) {
return _createSnapScrollSimulation(startOffset, endOffset, startVelocity, endVelocity);
}
double get minScrollOffset => double.NEGATIVE_INFINITY;
......@@ -108,33 +112,17 @@ class UnboundedBehavior extends ExtentScrollBehavior {
}
}
Simulation _createFlingScrollSimulation(double position, double velocity, double minScrollOffset, double maxScrollOffset, Tolerance tolerance) {
double startVelocity = velocity * _kSecondsPerMillisecond;
SpringDescription spring = new SpringDescription.withDampingRatio(mass: 1.0, springConstant: 170.0, ratio: 1.1);
ScrollSimulation simulation =
new ScrollSimulation(position, startVelocity, minScrollOffset, maxScrollOffset, spring, _kScrollDrag)
..tolerance = tolerance ?? _kDefaultScrollTolerance;
return simulation;
}
Simulation _createSnapScrollSimulation(double startOffset, double endOffset, double velocity) {
double startVelocity = velocity * _kSecondsPerMillisecond;
double endVelocity = velocity.sign * _kDefaultScrollTolerance.velocity;
return new FrictionSimulation.through(startOffset, endOffset, startVelocity, endVelocity);
}
/// A scroll behavior that lets the user scroll beyond the scroll bounds with some resistance
/// A scroll behavior that lets the user scroll beyond the scroll bounds with some resistance.
class OverscrollBehavior extends BoundedBehavior {
OverscrollBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 })
: super(contentExtent: contentExtent, containerExtent: containerExtent);
Simulation createFlingScrollSimulation(double position, double velocity, { Tolerance tolerance }) {
return _createFlingScrollSimulation(position, velocity, minScrollOffset, maxScrollOffset, tolerance);
Simulation createFlingScrollSimulation(double position, double velocity) {
return _createFlingScrollSimulation(position, velocity, minScrollOffset, maxScrollOffset);
}
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double velocity) {
return _createSnapScrollSimulation(startOffset, endOffset, velocity);
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double startVelocity, double endVelocity) {
return _createSnapScrollSimulation(startOffset, endOffset, startVelocity, endVelocity);
}
double applyCurve(double scrollOffset, double scrollDelta) {
......@@ -154,13 +142,13 @@ class OverscrollBehavior extends BoundedBehavior {
}
}
/// A scroll behavior that lets the user scroll beyond the scroll bounds only when the bounds are disjoint
/// A scroll behavior that lets the user scroll beyond the scroll bounds only when the bounds are disjoint.
class OverscrollWhenScrollableBehavior extends OverscrollBehavior {
bool get isScrollable => contentExtent > containerExtent;
Simulation createFlingScrollSimulation(double position, double velocity, { Tolerance tolerance }) {
Simulation createFlingScrollSimulation(double position, double velocity) {
if (isScrollable || position < minScrollOffset || position > maxScrollOffset)
return super.createFlingScrollSimulation(position, velocity, tolerance: tolerance);
return super.createFlingScrollSimulation(position, velocity);
return null;
}
......
......@@ -105,7 +105,8 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends OneSequenceGest
Offset velocity = tracker.getVelocity();
if (velocity != null && _isFlingGesture(velocity))
onEnd(velocity);
onEnd(Offset.zero);
else
onEnd(Offset.zero);
}
_velocityTrackers.clear();
}
......
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:math' as math;
import 'package:flutter/animation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'basic.dart';
import 'framework.dart';
import 'homogeneous_viewport.dart';
import 'scrollable.dart';
enum ItemsSnapAlignment { item, adjacentItem }
typedef void PageChangedCallback(int newPage);
class PageableList<T> extends Scrollable {
PageableList({
Key key,
initialScrollOffset,
ScrollDirection scrollDirection: ScrollDirection.vertical,
ScrollListener onScrollStart,
ScrollListener onScroll,
ScrollListener onScrollEnd,
SnapOffsetCallback snapOffsetCallback,
double snapAlignmentOffset: 0.0,
this.items,
this.itemBuilder,
this.itemsWrap: false,
this.itemsSnapAlignment: ItemsSnapAlignment.adjacentItem,
this.onPageChanged,
this.scrollableListPainter,
this.duration: const Duration(milliseconds: 200),
this.curve: Curves.ease
}) : super(
key: key,
initialScrollOffset: initialScrollOffset,
scrollDirection: scrollDirection,
onScrollStart: onScrollStart,
onScroll: onScroll,
onScrollEnd: onScrollEnd,
snapOffsetCallback: snapOffsetCallback,
snapAlignmentOffset: snapAlignmentOffset
);
final List<T> items;
final ItemBuilder<T> itemBuilder;
final ItemsSnapAlignment itemsSnapAlignment;
final bool itemsWrap;
final PageChangedCallback onPageChanged;
final ScrollableListPainter scrollableListPainter;
final Duration duration;
final Curve curve;
PageableListState<T, PageableList<T>> createState() => new PageableListState<T, PageableList<T>>();
}
class PageableListState<T, Config extends PageableList<T>> extends ScrollableState<Config> {
int get itemCount => config.items?.length ?? 0;
int _previousItemCount;
double pixelToScrollOffset(double value) {
final RenderBox box = context.findRenderObject();
if (box == null || !box.hasSize)
return 0.0;
final double pixelScrollExtent = config.scrollDirection == ScrollDirection.vertical ? box.size.height : box.size.width;
return pixelScrollExtent == 0.0 ? 0.0 : value / pixelScrollExtent;
}
void didUpdateConfig(Config oldConfig) {
super.didUpdateConfig(oldConfig);
bool scrollBehaviorUpdateNeeded = config.scrollDirection != oldConfig.scrollDirection;
if (config.itemsWrap != oldConfig.itemsWrap)
scrollBehaviorUpdateNeeded = true;
if (itemCount != _previousItemCount) {
_previousItemCount = itemCount;
scrollBehaviorUpdateNeeded = true;
}
if (scrollBehaviorUpdateNeeded)
_updateScrollBehavior();
}
void _updateScrollBehavior() {
// if you don't call this from build(), you must call it from setState().
if (config.scrollableListPainter != null)
config.scrollableListPainter.contentExtent = itemCount.toDouble();
scrollTo(scrollBehavior.updateExtents(
contentExtent: itemCount.toDouble(),
containerExtent: 1.0,
scrollOffset: scrollOffset
));
}
void dispatchOnScrollStart() {
super.dispatchOnScrollStart();
config.scrollableListPainter?.scrollStarted();
}
void dispatchOnScroll() {
super.dispatchOnScroll();
if (config.scrollableListPainter != null)
config.scrollableListPainter.scrollOffset = scrollOffset;
}
void dispatchOnScrollEnd() {
super.dispatchOnScrollEnd();
config.scrollableListPainter?.scrollEnded();
}
Widget buildContent(BuildContext context) {
if (itemCount != _previousItemCount) {
_previousItemCount = itemCount;
_updateScrollBehavior();
}
return new HomogeneousPageViewport(
builder: buildItems,
itemsWrap: config.itemsWrap,
itemCount: itemCount,
direction: config.scrollDirection,
startOffset: scrollOffset,
overlayPainter: config.scrollableListPainter
);
}
ScrollBehavior createScrollBehavior() {
return config.itemsWrap ? new UnboundedBehavior() : new OverscrollBehavior();
}
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
bool get snapScrollOffsetChanges => config.itemsSnapAlignment == ItemsSnapAlignment.item;
double snapScrollOffset(double newScrollOffset) {
double previousItemOffset = newScrollOffset.floorToDouble();
double nextItemOffset = newScrollOffset.ceilToDouble();
return (newScrollOffset - previousItemOffset < 0.5 ? previousItemOffset : nextItemOffset)
.clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset);
}
Future _flingToAdjacentItem(Offset velocity) {
double scrollVelocity = scrollDirectionVelocity(velocity);
double newScrollOffset = snapScrollOffset(scrollOffset + scrollVelocity.sign)
.clamp(snapScrollOffset(scrollOffset - 0.5), snapScrollOffset(scrollOffset + 0.5));
return scrollTo(newScrollOffset, duration: config.duration, curve: config.curve)
.then(_notifyPageChanged);
}
Future fling(Offset velocity) {
switch(config.itemsSnapAlignment) {
case ItemsSnapAlignment.adjacentItem:
return _flingToAdjacentItem(velocity);
default:
return super.fling(velocity).then(_notifyPageChanged);
}
}
Future settleScrollOffset() {
return scrollTo(snapScrollOffset(scrollOffset), duration: config.duration, curve: config.curve)
.then(_notifyPageChanged);
}
List<Widget> buildItems(BuildContext context, int start, int count) {
List<Widget> result = new List<Widget>();
int begin = config.itemsWrap ? start : math.max(0, start);
int end = config.itemsWrap ? begin + count : math.min(begin + count, config.items.length);
for (int i = begin; i < end; ++i)
result.add(config.itemBuilder(context, config.items[i % itemCount], i));
assert(result.every((Widget item) => item.key != null));
return result;
}
void _notifyPageChanged(_) {
if (config.onPageChanged != null)
config.onPageChanged(itemCount == 0 ? 0 : scrollOffset.floor() % itemCount);
}
}
......@@ -24,6 +24,11 @@ const double _kMillisecondsPerSecond = 1000.0;
const double _kMinFlingVelocity = -kMaxFlingVelocity * _kMillisecondsPerSecond;
const double _kMaxFlingVelocity = kMaxFlingVelocity * _kMillisecondsPerSecond;
final Tolerance kPixelScrollTolerance = new Tolerance(
velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
distance: 1.0 / ui.window.devicePixelRatio // logical pixels
);
typedef void ScrollListener(double scrollOffset);
typedef double SnapOffsetCallback(double scrollOffset);
......@@ -122,6 +127,18 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return new Offset(0.0, scrollOffset);
}
/// Convert a position or velocity measured in terms of pixels to a scrollOffset.
/// Scrollable gesture handlers convert their incoming values with this method.
/// Subclasses that define scrollOffset in units other than pixels must
/// override this method.
double pixelToScrollOffset(double pixelValue) => pixelValue;
double scrollDirectionVelocity(Offset scrollVelocity) {
return config.scrollDirection == ScrollDirection.horizontal
? -scrollVelocity.dx
: -scrollVelocity.dy;
}
ScrollBehavior _scrollBehavior;
ScrollBehavior createScrollBehavior();
ScrollBehavior get scrollBehavior {
......@@ -180,11 +197,32 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
}
Simulation _createFlingSimulation(double velocity) {
return scrollBehavior.createFlingScrollSimulation(scrollOffset, velocity);
/*
// Assume that we're rendering at atleast 15 FPS. Stop when we're
// scrolling less than one logical pixel per frame. We're essentially
// normalizing by the devicePixelRatio so that the threshold has the
// same effect independent of the device's pixel density.
double endVelocity = pixelToScrollOffset(15.0 * ui.window.devicePixelRatio);
// Similar to endVelocity. Stop scrolling when we're this close to
// destiniation scroll offset.
double endDistance = pixelToScrollOffset(0.5 * ui.window.devicePixelRatio);
*/
final double endVelocity = pixelToScrollOffset(kPixelScrollTolerance.velocity);
final double endDistance = pixelToScrollOffset(kPixelScrollTolerance.distance);
return scrollBehavior.createFlingScrollSimulation(scrollOffset, velocity)
..tolerance = new Tolerance(velocity: endVelocity.abs(), distance: endDistance);
}
double snapScrollOffset(double value) {
return config.snapOffsetCallback == null ? value : config.snapOffsetCallback(value);
}
bool get snapScrollOffsetChanges => config.snapOffsetCallback != null;
Simulation _createSnapSimulation(double velocity) {
if (velocity == null || config.snapOffsetCallback == null || !_scrollOffsetIsInBounds(scrollOffset))
if (!snapScrollOffsetChanges || velocity == 0.0 || !_scrollOffsetIsInBounds(scrollOffset))
return null;
Simulation simulation = _createFlingSimulation(velocity);
......@@ -195,14 +233,15 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
if (endScrollOffset.isNaN)
return null;
double snappedScrollOffset = config.snapOffsetCallback(endScrollOffset + config.snapAlignmentOffset);
double snappedScrollOffset = snapScrollOffset(endScrollOffset + config.snapAlignmentOffset);
double alignedScrollOffset = snappedScrollOffset - config.snapAlignmentOffset;
if (!_scrollOffsetIsInBounds(alignedScrollOffset))
return null;
double snapVelocity = velocity.abs() * (alignedScrollOffset - scrollOffset).sign;
double endVelocity = pixelToScrollOffset(kPixelScrollTolerance.velocity * velocity.sign);
Simulation toSnapSimulation =
scrollBehavior.createSnapScrollSimulation(scrollOffset, alignedScrollOffset, snapVelocity);
scrollBehavior.createSnapScrollSimulation(scrollOffset, alignedScrollOffset, snapVelocity, endVelocity);
if (toSnapSimulation == null)
return null;
......@@ -211,10 +250,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return new ClampedSimulation(toSnapSimulation, xMin: offsetMin, xMax: offsetMax);
}
Future _startToEndAnimation({ double velocity }) {
Future _startToEndAnimation(Offset scrollVelocity) {
double velocity = scrollDirectionVelocity(scrollVelocity);
_animation.stop();
Simulation simulation =
_createSnapSimulation(velocity) ?? _createFlingSimulation(velocity ?? 0.0);
Simulation simulation = _createSnapSimulation(velocity) ?? _createFlingSimulation(velocity);
if (simulation == null)
return new Future.value();
return _animation.animateWith(simulation);
......@@ -254,16 +293,16 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return scrollTo(newScrollOffset, duration: duration, curve: curve);
}
Future fling(Offset velocity) {
if (velocity != Offset.zero)
return _startToEndAnimation(velocity: _scrollVelocity(velocity));
Future fling(Offset scrollVelocity) {
if (scrollVelocity != Offset.zero)
return _startToEndAnimation(scrollVelocity);
if (!_animation.isAnimating)
return settleScrollOffset();
return new Future.value();
}
Future settleScrollOffset() {
return _startToEndAnimation();
return _startToEndAnimation(Offset.zero);
}
void dispatchOnScrollStart() {
......@@ -282,13 +321,6 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
config.onScrollEnd(_scrollOffset);
}
double _scrollVelocity(ui.Offset velocity) {
double scrollVelocity = config.scrollDirection == ScrollDirection.horizontal
? -velocity.dx
: -velocity.dy;
return scrollVelocity.clamp(_kMinFlingVelocity, _kMaxFlingVelocity) / _kMillisecondsPerSecond;
}
void _handlePointerDown(_) {
_animation.stop();
}
......@@ -300,11 +332,16 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
void _handleDragUpdate(double delta) {
// We negate the delta here because a positive scroll offset moves the
// the content up (or to the left) rather than down (or the right).
scrollBy(-delta);
scrollBy(pixelToScrollOffset(-delta));
}
Future _handleDragEnd(Offset velocity) {
return fling(velocity).then((_) {
double _toScrollVelocity(double velocity) {
return pixelToScrollOffset(velocity.clamp(_kMinFlingVelocity, _kMaxFlingVelocity) / _kMillisecondsPerSecond);
}
Future _handleDragEnd(Offset pixelScrollVelocity) {
final Offset scrollVelocity = new Offset(_toScrollVelocity(pixelScrollVelocity.dx), _toScrollVelocity(pixelScrollVelocity.dy));
return fling(scrollVelocity).then((_) {
dispatchOnScrollEnd();
});
}
......@@ -690,71 +727,6 @@ class ScrollableListState<T, Config extends ScrollableList<T>> extends Scrollabl
}
}
typedef void PageChangedCallback(int newPage);
class PageableList<T> extends ScrollableList<T> {
PageableList({
Key key,
int initialPage,
ScrollDirection scrollDirection: ScrollDirection.horizontal,
ScrollListener onScroll,
List<T> items,
ItemBuilder<T> itemBuilder,
bool itemsWrap: false,
double itemExtent,
this.onPageChanged,
EdgeDims padding,
this.duration: const Duration(milliseconds: 200),
this.curve: Curves.ease
}) : super(
key: key,
initialScrollOffset: initialPage == null ? null : initialPage * itemExtent,
scrollDirection: scrollDirection,
onScroll: onScroll,
items: items,
itemBuilder: itemBuilder,
itemsWrap: itemsWrap,
itemExtent: itemExtent,
padding: padding
);
final Duration duration;
final Curve curve;
final PageChangedCallback onPageChanged;
PageableListState<T> createState() => new PageableListState<T>();
}
class PageableListState<T> extends ScrollableListState<T, PageableList<T>> {
double _snapScrollOffset(double newScrollOffset) {
double scaledScrollOffset = newScrollOffset / config.itemExtent;
double previousScrollOffset = scaledScrollOffset.floor() * config.itemExtent;
double nextScrollOffset = scaledScrollOffset.ceil() * config.itemExtent;
double delta = newScrollOffset - previousScrollOffset;
return (delta < config.itemExtent / 2.0 ? previousScrollOffset : nextScrollOffset)
.clamp(scrollBehavior.minScrollOffset, scrollBehavior.maxScrollOffset);
}
Future fling(ui.Offset velocity) {
double scrollVelocity = _scrollVelocity(velocity);
double newScrollOffset = _snapScrollOffset(scrollOffset + scrollVelocity.sign * config.itemExtent)
.clamp(_snapScrollOffset(scrollOffset - config.itemExtent / 2.0),
_snapScrollOffset(scrollOffset + config.itemExtent / 2.0));
return scrollTo(newScrollOffset, duration: config.duration, curve: config.curve).then(_notifyPageChanged);
}
int get currentPage => (scrollOffset / config.itemExtent).floor() % itemCount;
void _notifyPageChanged(_) {
if (config.onPageChanged != null)
config.onPageChanged(currentPage);
}
Future settleScrollOffset() {
return scrollTo(_snapScrollOffset(scrollOffset), duration: config.duration, curve: config.curve).then(_notifyPageChanged);
}
}
/// A general scrollable list for a large number of children that might not all
/// have the same height. Prefer [ScrollableWidgetList] when all the children
/// have the same height because it can use that property to be more efficient.
......
......@@ -28,6 +28,7 @@ export 'src/widgets/notification_listener.dart';
export 'src/widgets/overlay.dart';
export 'src/widgets/page_storage.dart';
export 'src/widgets/pages.dart';
export 'src/widgets/pageable_list.dart';
export 'src/widgets/placeholder.dart';
export 'src/widgets/routes.dart';
export 'src/widgets/scrollable.dart';
......
......@@ -27,7 +27,6 @@ Widget buildFrame() {
items: pages,
itemBuilder: buildPage,
itemsWrap: itemsWrap,
itemExtent: pageSize.width,
scrollDirection: ScrollDirection.horizontal,
onPageChanged: (int page) { currentPage = page; }
);
......
......@@ -57,7 +57,7 @@ Future fling(double velocity) {
}
void main() {
test('ScrollableList snap scrolling, fling(-800)', () {
test('ScrollableList snap scrolling, fling(-0.8)', () {
testWidgets((WidgetTester tester) {
tester.pumpWidget(buildFrame());
......@@ -67,7 +67,7 @@ void main() {
Duration dt = const Duration(seconds: 2);
fling(-800.0);
fling(-0.8);
tester.pump(); // Start the scheduler at 0.0
tester.pump(dt);
expect(scrollOffset, closeTo(200.0, 1.0));
......@@ -76,7 +76,7 @@ void main() {
tester.pump();
expect(scrollOffset, 0.0);
fling(-2000.0);
fling(-2.0);
tester.pump();
tester.pump(dt);
expect(scrollOffset, closeTo(400.0, 1.0));
......@@ -85,7 +85,7 @@ void main() {
tester.pump();
expect(scrollOffset, 400.0);
fling(800.0);
fling(0.8);
tester.pump();
tester.pump(dt);
expect(scrollOffset, closeTo(0.0, 1.0));
......@@ -94,7 +94,7 @@ void main() {
tester.pump();
expect(scrollOffset, 800.0);
fling(2000.0);
fling(2.0);
tester.pump();
tester.pump(dt);
expect(scrollOffset, closeTo(200.0, 1.0));
......@@ -104,7 +104,7 @@ void main() {
expect(scrollOffset, 800.0);
bool completed = false;
fling(2000.0).then((_) {
fling(2.0).then((_) {
completed = true;
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