Breaks the moveBy call from drag and dragFrom into two separate calls and changes the default behavior of DragStartBehavior to DragStartBehavior.start (#26438)

* Breaking change which sets the default DragStartBehavior to DragStartBehavior.start and changes WidgetTester.drag and WidgetTester.dragFrom by breaking the moveBy function call into multiple pieces.
This commit is contained in:
jslavitz 2019-02-25 14:15:31 -08:00 committed by GitHub
parent 62e55a45d4
commit 47724f97fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 532 additions and 111 deletions

View File

@ -60,7 +60,7 @@ class CupertinoSwitch extends StatefulWidget {
@required this.value, @required this.value,
@required this.onChanged, @required this.onChanged,
this.activeColor, this.activeColor,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(dragStartBehavior != null), }) : assert(dragStartBehavior != null),
super(key: key); super(key: key);
@ -97,7 +97,6 @@ class CupertinoSwitch extends StatefulWidget {
/// [CupertinoTheme] in accordance to native iOS behavior. /// [CupertinoTheme] in accordance to native iOS behavior.
final Color activeColor; final Color activeColor;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// {@template flutter.cupertino.switch.dragStartBehavior} /// {@template flutter.cupertino.switch.dragStartBehavior}
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
@ -110,7 +109,7 @@ class CupertinoSwitch extends StatefulWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///
@ -149,7 +148,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
this.activeColor, this.activeColor,
this.onChanged, this.onChanged,
this.vsync, this.vsync,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : super(key: key); }) : super(key: key);
final bool value; final bool value;
@ -202,7 +201,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox {
ValueChanged<bool> onChanged, ValueChanged<bool> onChanged,
@required TextDirection textDirection, @required TextDirection textDirection,
@required TickerProvider vsync, @required TickerProvider vsync,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : assert(value != null), }) : assert(value != null),
assert(activeColor != null), assert(activeColor != null),
assert(vsync != null), assert(vsync != null),

View File

@ -54,6 +54,10 @@ const Duration kZoomControlsTimeout = Duration(milliseconds: 3000);
/// the gesture is a scroll gesture, or, inversely, the maximum distance that a /// the gesture is a scroll gesture, or, inversely, the maximum distance that a
/// touch can travel before the framework becomes confident that it is not a /// touch can travel before the framework becomes confident that it is not a
/// tap. /// tap.
///
/// A total delta less than or equal to [kTouchSlop] is not considered to be a
/// drag, whereas if the delta is greater than [kTouchSlop] it is considered to
/// be a drag.
// This value was empirically derived. We started at 8.0 and increased it to // This value was empirically derived. We started at 8.0 and increased it to
// 18.0 after getting complaints that it was too difficult to hit targets. // 18.0 after getting complaints that it was too difficult to hit targets.
const double kTouchSlop = 18.0; // Logical pixels const double kTouchSlop = 18.0; // Logical pixels

View File

@ -54,7 +54,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
/// [dragStartBehavior] must not be null. /// [dragStartBehavior] must not be null.
DragGestureRecognizer({ DragGestureRecognizer({
Object debugOwner, Object debugOwner,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(dragStartBehavior != null), }) : assert(dragStartBehavior != null),
super(debugOwner: debugOwner); super(debugOwner: debugOwner);

View File

@ -254,7 +254,7 @@ class DayPicker extends StatelessWidget {
@required this.lastDate, @required this.lastDate,
@required this.displayedMonth, @required this.displayedMonth,
this.selectableDayPredicate, this.selectableDayPredicate,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(currentDate != null), assert(currentDate != null),
assert(onChanged != null), assert(onChanged != null),
@ -287,7 +287,6 @@ class DayPicker extends StatelessWidget {
/// Optional user supplied predicate function to customize selectable days. /// Optional user supplied predicate function to customize selectable days.
final SelectableDayPredicate selectableDayPredicate; final SelectableDayPredicate selectableDayPredicate;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
/// If set to [DragStartBehavior.start], the drag gesture used to scroll a /// If set to [DragStartBehavior.start], the drag gesture used to scroll a
@ -299,7 +298,7 @@ class DayPicker extends StatelessWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///
@ -528,7 +527,7 @@ class MonthPicker extends StatefulWidget {
@required this.firstDate, @required this.firstDate,
@required this.lastDate, @required this.lastDate,
this.selectableDayPredicate, this.selectableDayPredicate,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(onChanged != null), assert(onChanged != null),
assert(!firstDate.isAfter(lastDate)), assert(!firstDate.isAfter(lastDate)),
@ -791,7 +790,7 @@ class YearPicker extends StatefulWidget {
@required this.onChanged, @required this.onChanged,
@required this.firstDate, @required this.firstDate,
@required this.lastDate, @required this.lastDate,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(onChanged != null), assert(onChanged != null),
assert(!firstDate.isAfter(lastDate)), assert(!firstDate.isAfter(lastDate)),

View File

@ -180,7 +180,7 @@ class DrawerController extends StatefulWidget {
@required this.child, @required this.child,
@required this.alignment, @required this.alignment,
this.drawerCallback, this.drawerCallback,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(child != null), }) : assert(child != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(alignment != null), assert(alignment != null),
@ -200,7 +200,6 @@ class DrawerController extends StatefulWidget {
/// Optional callback that is called when a [Drawer] is opened or closed. /// Optional callback that is called when a [Drawer] is opened or closed.
final DrawerCallback drawerCallback; final DrawerCallback drawerCallback;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// {@template flutter.material.drawer.dragStartBehavior} /// {@template flutter.material.drawer.dragStartBehavior}
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
@ -213,7 +212,7 @@ class DrawerController extends StatefulWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///

View File

@ -75,7 +75,7 @@ class PaginatedDataTable extends StatefulWidget {
this.rowsPerPage = defaultRowsPerPage, this.rowsPerPage = defaultRowsPerPage,
this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10], this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10],
this.onRowsPerPageChanged, this.onRowsPerPageChanged,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
@required this.source @required this.source
}) : assert(header != null), }) : assert(header != null),
assert(columns != null), assert(columns != null),

View File

@ -876,8 +876,8 @@ class Scaffold extends StatefulWidget {
this.resizeToAvoidBottomPadding, this.resizeToAvoidBottomPadding,
this.resizeToAvoidBottomInset, this.resizeToAvoidBottomInset,
this.primary = true, this.primary = true,
this.drawerDragStartBehavior = DragStartBehavior.start,
this.extendBody = false, this.extendBody = false,
this.drawerDragStartBehavior = DragStartBehavior.down,
}) : assert(primary != null), }) : assert(primary != null),
assert(extendBody != null), assert(extendBody != null),
assert(drawerDragStartBehavior != null), assert(drawerDragStartBehavior != null),

View File

@ -73,7 +73,7 @@ class Switch extends StatefulWidget {
this.activeThumbImage, this.activeThumbImage,
this.inactiveThumbImage, this.inactiveThumbImage,
this.materialTapTargetSize, this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : _switchType = _SwitchType.material, }) : _switchType = _SwitchType.material,
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
super(key: key); super(key: key);
@ -97,7 +97,7 @@ class Switch extends StatefulWidget {
this.activeThumbImage, this.activeThumbImage,
this.inactiveThumbImage, this.inactiveThumbImage,
this.materialTapTargetSize, this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : _switchType = _SwitchType.adaptive, }) : _switchType = _SwitchType.adaptive,
super(key: key); super(key: key);

View File

@ -562,7 +562,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
this.labelPadding, this.labelPadding,
this.unselectedLabelColor, this.unselectedLabelColor,
this.unselectedLabelStyle, this.unselectedLabelStyle,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
this.onTap, this.onTap,
}) : assert(tabs != null), }) : assert(tabs != null),
assert(isScrollable != null), assert(isScrollable != null),
@ -1057,7 +1057,7 @@ class TabBarView extends StatefulWidget {
@required this.children, @required this.children,
this.controller, this.controller,
this.physics, this.physics,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(children != null), }) : assert(children != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
super(key: key); super(key: key);

View File

@ -143,7 +143,7 @@ class TextField extends StatefulWidget {
this.cursorColor, this.cursorColor,
this.keyboardAppearance, this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0), this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.onTap, this.onTap,
this.buildCounter, this.buildCounter,

View File

@ -91,7 +91,7 @@ class Dismissible extends StatefulWidget {
this.dismissThresholds = const <DismissDirection, double>{}, this.dismissThresholds = const <DismissDirection, double>{},
this.movementDuration = const Duration(milliseconds: 200), this.movementDuration = const Duration(milliseconds: 200),
this.crossAxisEndOffset = 0.0, this.crossAxisEndOffset = 0.0,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(key != null), }) : assert(key != null),
assert(secondaryBackground != null ? background != null : true), assert(secondaryBackground != null ? background != null : true),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
@ -162,7 +162,6 @@ class Dismissible extends StatefulWidget {
/// it is positive or negative. /// it is positive or negative.
final double crossAxisEndOffset; final double crossAxisEndOffset;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
/// If set to [DragStartBehavior.start], the drag gesture used to dismiss a /// If set to [DragStartBehavior.start], the drag gesture used to dismiss a
@ -173,7 +172,7 @@ class Dismissible extends StatefulWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///

View File

@ -231,7 +231,7 @@ class EditableText extends StatefulWidget {
this.paintCursorAboveText = false, this.paintCursorAboveText = false,
this.scrollPadding = const EdgeInsets.all(20.0), this.scrollPadding = const EdgeInsets.all(20.0),
this.keyboardAppearance = Brightness.light, this.keyboardAppearance = Brightness.light,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection, this.enableInteractiveSelection,
}) : assert(controller != null), }) : assert(controller != null),
assert(focusNode != null), assert(focusNode != null),

View File

@ -186,7 +186,7 @@ class GestureDetector extends StatelessWidget {
this.onScaleEnd, this.onScaleEnd,
this.behavior, this.behavior,
this.excludeFromSemantics = false, this.excludeFromSemantics = false,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(excludeFromSemantics != null), }) : assert(excludeFromSemantics != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(() { assert(() {
@ -373,7 +373,6 @@ class GestureDetector extends StatelessWidget {
/// duplication of information. /// duplication of information.
final bool excludeFromSemantics; final bool excludeFromSemantics;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
/// If set to [DragStartBehavior.start], gesture drag behavior will /// If set to [DragStartBehavior.start], gesture drag behavior will
@ -384,7 +383,7 @@ class GestureDetector extends StatelessWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// Only the [onStart] callbacks for the [VerticalDragGestureRecognizer], /// Only the [onStart] callbacks for the [VerticalDragGestureRecognizer],
/// [HorizontalDragGestureRecognizer] and [PanGestureRecognizer] are affected /// [HorizontalDragGestureRecognizer] and [PanGestureRecognizer] are affected

View File

@ -189,7 +189,7 @@ class NestedScrollView extends StatefulWidget {
this.physics, this.physics,
@required this.headerSliverBuilder, @required this.headerSliverBuilder,
@required this.body, @required this.body,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(scrollDirection != null), }) : assert(scrollDirection != null),
assert(reverse != null), assert(reverse != null),
assert(headerSliverBuilder != null), assert(headerSliverBuilder != null),
@ -371,7 +371,7 @@ class _NestedScrollViewCustomScrollView extends CustomScrollView {
@required ScrollController controller, @required ScrollController controller,
@required List<Widget> slivers, @required List<Widget> slivers,
@required this.handle, @required this.handle,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super( }) : super(
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
reverse: reverse, reverse: reverse,

View File

@ -425,7 +425,7 @@ class PageView extends StatefulWidget {
this.pageSnapping = true, this.pageSnapping = true,
this.onPageChanged, this.onPageChanged,
List<Widget> children = const <Widget>[], List<Widget> children = const <Widget>[],
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : controller = controller ?? _defaultPageController, }) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildListDelegate(children), childrenDelegate = SliverChildListDelegate(children),
super(key: key); super(key: key);
@ -452,7 +452,7 @@ class PageView extends StatefulWidget {
this.onPageChanged, this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder, @required IndexedWidgetBuilder itemBuilder,
int itemCount, int itemCount,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : controller = controller ?? _defaultPageController, }) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildBuilderDelegate(itemBuilder, childCount: itemCount), childrenDelegate = SliverChildBuilderDelegate(itemBuilder, childCount: itemCount),
super(key: key); super(key: key);
@ -468,7 +468,7 @@ class PageView extends StatefulWidget {
this.pageSnapping = true, this.pageSnapping = true,
this.onPageChanged, this.onPageChanged,
@required this.childrenDelegate, @required this.childrenDelegate,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(childrenDelegate != null), }) : assert(childrenDelegate != null),
controller = controller ?? _defaultPageController, controller = controller ?? _defaultPageController,
super(key: key); super(key: key);

View File

@ -312,7 +312,6 @@ class ScrollDragController implements Drag {
// May be null for proxied drags like via accessibility. // May be null for proxied drags like via accessibility.
return offset; return offset;
} }
if (offset == 0.0) { if (offset == 0.0) {
if (motionStartDistanceThreshold != null && if (motionStartDistanceThreshold != null &&
_offsetSinceLastStop == null && _offsetSinceLastStop == null &&

View File

@ -69,7 +69,7 @@ abstract class ScrollView extends StatelessWidget {
this.anchor = 0.0, this.anchor = 0.0,
this.cacheExtent, this.cacheExtent,
this.semanticChildCount, this.semanticChildCount,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(scrollDirection != null), }) : assert(scrollDirection != null),
assert(reverse != null), assert(reverse != null),
assert(shrinkWrap != null), assert(shrinkWrap != null),
@ -454,7 +454,7 @@ class CustomScrollView extends ScrollView {
double cacheExtent, double cacheExtent,
this.slivers = const <Widget>[], this.slivers = const <Widget>[],
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super( }) : super(
key: key, key: key,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
@ -500,7 +500,7 @@ abstract class BoxScrollView extends ScrollView {
this.padding, this.padding,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super( }) : super(
key: key, key: key,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
@ -802,7 +802,7 @@ class ListView extends BoxScrollView {
double cacheExtent, double cacheExtent,
List<Widget> children = const <Widget>[], List<Widget> children = const <Widget>[],
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : childrenDelegate = SliverChildListDelegate( }) : childrenDelegate = SliverChildListDelegate(
children, children,
addAutomaticKeepAlives: addAutomaticKeepAlives, addAutomaticKeepAlives: addAutomaticKeepAlives,
@ -866,7 +866,7 @@ class ListView extends BoxScrollView {
bool addSemanticIndexes = true, bool addSemanticIndexes = true,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : childrenDelegate = SliverChildBuilderDelegate( }) : childrenDelegate = SliverChildBuilderDelegate(
itemBuilder, itemBuilder,
childCount: itemCount, childCount: itemCount,
@ -1320,7 +1320,7 @@ class GridView extends BoxScrollView {
@required this.childrenDelegate, @required this.childrenDelegate,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : assert(gridDelegate != null), }) : assert(gridDelegate != null),
assert(childrenDelegate != null), assert(childrenDelegate != null),
super( super(
@ -1370,7 +1370,7 @@ class GridView extends BoxScrollView {
double cacheExtent, double cacheExtent,
List<Widget> children = const <Widget>[], List<Widget> children = const <Widget>[],
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount( }) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount, crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing, mainAxisSpacing: mainAxisSpacing,
@ -1429,7 +1429,7 @@ class GridView extends BoxScrollView {
bool addSemanticIndexes = true, bool addSemanticIndexes = true,
List<Widget> children = const <Widget>[], List<Widget> children = const <Widget>[],
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.down, DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent( }) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent, maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing, mainAxisSpacing: mainAxisSpacing,

View File

@ -81,7 +81,7 @@ class Scrollable extends StatefulWidget {
@required this.viewportBuilder, @required this.viewportBuilder,
this.excludeFromSemantics = false, this.excludeFromSemantics = false,
this.semanticChildCount, this.semanticChildCount,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(axisDirection != null), }) : assert(axisDirection != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(viewportBuilder != null), assert(viewportBuilder != null),
@ -194,7 +194,7 @@ class Scrollable extends StatefulWidget {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///

View File

@ -204,7 +204,7 @@ class SingleChildScrollView extends StatelessWidget {
this.physics, this.physics,
this.controller, this.controller,
this.child, this.child,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(scrollDirection != null), }) : assert(scrollDirection != null),
assert(dragStartBehavior != null), assert(dragStartBehavior != null),
assert(!(controller != null && primary == true), assert(!(controller != null && primary == true),

View File

@ -230,7 +230,7 @@ class TextSelectionOverlay {
@required this.renderObject, @required this.renderObject,
this.selectionControls, this.selectionControls,
this.selectionDelegate, this.selectionDelegate,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : assert(value != null), }) : assert(value != null),
assert(context != null), assert(context != null),
_value = value { _value = value {
@ -265,7 +265,6 @@ class TextSelectionOverlay {
/// text field. /// text field.
final TextSelectionDelegate selectionDelegate; final TextSelectionDelegate selectionDelegate;
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
/// Determines the way that drag start behavior is handled. /// Determines the way that drag start behavior is handled.
/// ///
/// If set to [DragStartBehavior.start], handle drag behavior will /// If set to [DragStartBehavior.start], handle drag behavior will
@ -276,7 +275,7 @@ class TextSelectionOverlay {
/// animation smoother and setting it to [DragStartBehavior.down] will make /// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive. /// drag behavior feel slightly more reactive.
/// ///
/// By default, the drag start behavior is [DragStartBehavior.down]. /// By default, the drag start behavior is [DragStartBehavior.start].
/// ///
/// See also: /// See also:
/// ///
@ -468,7 +467,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
@required this.onSelectionHandleChanged, @required this.onSelectionHandleChanged,
@required this.onSelectionHandleTapped, @required this.onSelectionHandleTapped,
@required this.selectionControls, @required this.selectionControls,
this.dragStartBehavior = DragStartBehavior.down, this.dragStartBehavior = DragStartBehavior.start,
}) : super(key: key); }) : super(key: key);
final TextSelection selection; final TextSelection selection;

View File

@ -8,7 +8,7 @@ import 'package:flutter/semantics.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
// scrolling by this offset will move the picker to the next item // scrolling by this offset will move the picker to the next item
const Offset _kRowOffset = Offset(0.0, -32.0); const Offset _kRowOffset = Offset(0.0, -50.0);
void main() { void main() {
group('Countdown timer picker', () { group('Countdown timer picker', () {
@ -280,7 +280,7 @@ void main() {
), ),
); );
await tester.drag(find.text('10'), const Offset(0.0, 32.0)); await tester.drag(find.text('10'), const Offset(0.0, 32.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
@ -301,7 +301,7 @@ void main() {
), ),
); );
await tester.drag(find.text('9'), const Offset(0.0, 32.0)); await tester.drag(find.text('9'), const Offset(0.0, 32.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
@ -487,7 +487,8 @@ void main() {
), ),
); );
await tester.drag(find.text('March'), const Offset(0.0, 32.0)); await tester.drag(find.text('March'), const Offset(0, 32.0), touchSlopY: 0.0);
// Momentarily, the 2018 and the incorrect 30 of February is aligned. // Momentarily, the 2018 and the incorrect 30 of February is aligned.
expect( expect(
tester.getTopLeft(find.text('2018')).dy, tester.getTopLeft(find.text('2018')).dy,
@ -525,15 +526,14 @@ void main() {
), ),
); );
await tester.drag(find.text('27'), const Offset(0.0, -32.0)); await tester.drag(find.text('27'), const Offset(0.0, -32.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
expect( expect(
date, date,
DateTime(2018, 2, 28), DateTime(2018, 2, 28),
); );
await tester.drag(find.text('28'), const Offset(0.0, -32.0), touchSlopY: 0.0);
await tester.drag(find.text('28'), const Offset(0.0, -32.0));
await tester.pump(); // Once to trigger the post frame animate call. await tester.pump(); // Once to trigger the post frame animate call.
// Callback doesn't transiently go into invalid dates. // Callback doesn't transiently go into invalid dates.
@ -706,6 +706,8 @@ void main() {
), ),
); );
const Offset deltaOffset = Offset(0.0, -18.0);
// 11:59 -> 12:59 // 11:59 -> 12:59
await tester.drag(find.text('11'), _kRowOffset); await tester.drag(find.text('11'), _kRowOffset);
await tester.pump(); await tester.pump();
@ -721,14 +723,14 @@ void main() {
expect(date, DateTime(2018, 1, 1, 11, 59)); expect(date, DateTime(2018, 1, 1, 11, 59));
// 11:59 -> 9:59 // 11:59 -> 9:59
await tester.drag(find.text('11'), -_kRowOffset * 2); await tester.drag(find.text('11'), -((_kRowOffset - deltaOffset) * 2 + deltaOffset));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));
expect(date, DateTime(2018, 1, 1, 9, 59)); expect(date, DateTime(2018, 1, 1, 9, 59));
// 9:59 -> 15:59 // 9:59 -> 15:59
await tester.drag(find.text('9'), _kRowOffset * 6); await tester.drag(find.text('9'), (_kRowOffset - deltaOffset) * 6 + deltaOffset);
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 500)); await tester.pump(const Duration(milliseconds: 500));

View File

@ -298,7 +298,7 @@ void main() {
); );
// Drag it by a bit but not enough to move to the next item. // Drag it by a bit but not enough to move to the next item.
await tester.drag(find.text('10'), const Offset(0.0, 30.0)); await tester.drag(find.text('10'), const Offset(0.0, 30.0), touchSlopY: 0.0);
// The item that was in the center now moved a bit. // The item that was in the center now moved a bit.
expect( expect(
@ -315,7 +315,7 @@ void main() {
expect(selectedItems.isEmpty, true); expect(selectedItems.isEmpty, true);
// Drag it by enough to move to the next item. // Drag it by enough to move to the next item.
await tester.drag(find.text('10'), const Offset(0.0, 70.0)); await tester.drag(find.text('10'), const Offset(0.0, 70.0), touchSlopY: 0.0);
await tester.pumpAndSettle(); await tester.pumpAndSettle();

View File

@ -117,7 +117,7 @@ void main() {
); );
// Drag down but not enough to trigger the refresh. // Drag down but not enough to trigger the refresh.
await tester.drag(find.text('0'), const Offset(0.0, 50.0)); await tester.drag(find.text('0'), const Offset(0.0, 50.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
// The function is referenced once while passing into CupertinoSliverRefreshControl // The function is referenced once while passing into CupertinoSliverRefreshControl
@ -191,7 +191,7 @@ void main() {
); );
// Drag down but not enough to trigger the refresh. // Drag down but not enough to trigger the refresh.
await tester.drag(find.text('0'), const Offset(0.0, 50.0)); await tester.drag(find.text('0'), const Offset(0.0, 50.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
await tester.pump(const Duration(milliseconds: 20)); await tester.pump(const Duration(milliseconds: 20));
await tester.pump(const Duration(milliseconds: 20)); await tester.pump(const Duration(milliseconds: 20));
@ -317,7 +317,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
// Let it start snapping back. // Let it start snapping back.
await tester.pump(const Duration(milliseconds: 50)); await tester.pump(const Duration(milliseconds: 50));
@ -394,7 +394,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
verify(mockHelper.builder( verify(mockHelper.builder(
@ -411,7 +411,7 @@ void main() {
Rect.fromLTRB(0.0, 0.0, 800.0, 150.0), Rect.fromLTRB(0.0, 0.0, 800.0, 150.0),
); );
await tester.drag(find.text('0'), const Offset(0.0, -300.0)); await tester.drag(find.text('0'), const Offset(0.0, -300.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
// Refresh indicator still being told to layout the same way. // Refresh indicator still being told to layout the same way.
@ -474,7 +474,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
verify(mockHelper.builder( verify(mockHelper.builder(
any, any,
@ -549,7 +549,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0);
await tester.pump(); await tester.pump();
verify(mockHelper.builder( verify(mockHelper.builder(
any, any,
@ -639,7 +639,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
verify(mockHelper.refreshTask()); verify(mockHelper.refreshTask());
@ -670,7 +670,7 @@ void main() {
// Start another drag by an amount that would have been enough to // Start another drag by an amount that would have been enough to
// trigger another refresh if it were in the right state. // trigger another refresh if it were in the right state.
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
// Instead, it's still in the done state because the sliver never // Instead, it's still in the done state because the sliver never
@ -692,7 +692,7 @@ void main() {
); );
// Start another drag. It's now in drag mode. // Start another drag. It's now in drag mode.
await tester.drag(find.text('0'), const Offset(0.0, 40.0)); await tester.drag(find.text('0'), const Offset(0.0, 40.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
verify(mockHelper.builder( verify(mockHelper.builder(
any, any,
@ -908,7 +908,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 150.0)); await tester.drag(find.text('0'), const Offset(0.0, 150.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
verify(mockHelper.builder( verify(mockHelper.builder(
any, any,
@ -1101,7 +1101,7 @@ void main() {
), ),
); );
await tester.drag(find.text('0'), const Offset(0.0, 100.0)); await tester.drag(find.text('0'), const Offset(0.0, 100.0), touchSlopY: 0.0);
await tester.pump(); await tester.pump();
expect( expect(
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))), CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),

View File

@ -255,7 +255,6 @@ void main() {
return Center( return Center(
child: CupertinoSwitch( child: CupertinoSwitch(
value: value, value: value,
dragStartBehavior: DragStartBehavior.down,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
value = newValue; value = newValue;
@ -270,21 +269,21 @@ void main() {
expect(value, isFalse); expect(value, isFalse);
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0)); await tester.drag(find.byType(CupertinoSwitch), const Offset(-48.0, 0.0));
expect(value, isFalse); expect(value, isFalse);
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0)); await tester.drag(find.byType(CupertinoSwitch), const Offset(48.0, 0.0));
expect(value, isTrue); expect(value, isTrue);
await tester.pump(); await tester.pump();
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0)); await tester.drag(find.byType(CupertinoSwitch), const Offset(48.0, 0.0));
expect(value, isTrue); expect(value, isTrue);
await tester.pump(); await tester.pump();
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0)); await tester.drag(find.byType(CupertinoSwitch), const Offset(-48.0, 0.0));
expect(value, isFalse); expect(value, isFalse);
}); });

View File

@ -58,9 +58,6 @@ void main() {
tester.route(pointer.move(const Offset(20.0, 30.0))); // moved 10 horizontally and 20 vertically which is 22 total tester.route(pointer.move(const Offset(20.0, 30.0))); // moved 10 horizontally and 20 vertically which is 22 total
expect(didStartPan, isTrue); // 22 > 18 expect(didStartPan, isTrue); // 22 > 18
didStartPan = false; didStartPan = false;
// TODO(jslavitz): revert this testing change.
expect(updatedScrollDelta, const Offset(10.0, 20.0));
updatedScrollDelta = null;
expect(didEndPan, isFalse); expect(didEndPan, isFalse);
expect(didTap, isFalse); expect(didTap, isFalse);
@ -82,6 +79,58 @@ void main() {
tap.dispose(); tap.dispose();
}); });
testGesture('Should report most recent point to onStart by default', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
final VerticalDragGestureRecognizer competingDrag = VerticalDragGestureRecognizer();
Offset positionAtOnStart;
drag.onStart = (DragStartDetails details) {
positionAtOnStart = details.globalPosition;
};
final TestPointer pointer = TestPointer(5);
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
drag.addPointer(down);
competingDrag.addPointer(down);
tester.closeArena(5);
tester.route(down);
tester.route(pointer.move(const Offset(30.0, 0.0)));
drag.dispose();
competingDrag.dispose();
expect(positionAtOnStart, const Offset(30.0, 00.0));
});
testGesture('Should report most recent point to onStart with a start configuration', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag =
HorizontalDragGestureRecognizer();
final VerticalDragGestureRecognizer competingDrag = VerticalDragGestureRecognizer();
Offset positionAtOnStart;
drag.onStart = (DragStartDetails details) {
positionAtOnStart = details.globalPosition;
};
Offset updateOffset;
drag.onUpdate = (DragUpdateDetails details) {
updateOffset = details.globalPosition;
};
final TestPointer pointer = TestPointer(5);
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
drag.addPointer(down);
competingDrag.addPointer(down);
tester.closeArena(5);
tester.route(down);
tester.route(pointer.move(const Offset(30.0, 0.0)));
drag.dispose();
competingDrag.dispose();
expect(positionAtOnStart, const Offset(30.0, 0.0));
expect(updateOffset, null);
});
testGesture('Should recognize drag', (GestureTester tester) { testGesture('Should recognize drag', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down; final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;

View File

@ -102,7 +102,7 @@ void main() {
didStartPan = true; didStartPan = true;
}, },
onPanUpdate: (DragUpdateDetails details) { onPanUpdate: (DragUpdateDetails details) {
panDelta = details.delta; panDelta = panDelta == null ? details.delta : panDelta + details.delta;
}, },
onPanEnd: (DragEndDetails details) { onPanEnd: (DragEndDetails details) {
didEndPan = true; didEndPan = true;

View File

@ -35,7 +35,7 @@ void main() {
await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr)); await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr));
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('1'), const Offset(-300.0, 0.0)); await tester.drag(find.text('1'), const Offset(-300.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 1 // -10..280 = 1
@ -52,7 +52,7 @@ void main() {
// if item 3 was a bit wider, such that its center was past the 800px mark, this would fail, // if item 3 was a bit wider, such that its center was past the 800px mark, this would fail,
// because it wouldn't be hit tested when scrolling from its center, as drag() does. // because it wouldn't be hit tested when scrolling from its center, as drag() does.
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(-290.0, 0.0)); await tester.drag(find.text('3'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 2 // -10..280 = 2
@ -66,7 +66,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(0.0, -290.0)); await tester.drag(find.text('3'), const Offset(0.0, -290.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// unchanged // unchanged
expect(find.text('0'), findsNothing); expect(find.text('0'), findsNothing);
@ -77,7 +77,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(-290.0, 0.0)); await tester.drag(find.text('3'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 3 // -10..280 = 3
@ -96,7 +96,7 @@ void main() {
// to move item 3 entirely off screen therefore takes: // to move item 3 entirely off screen therefore takes:
// 60 + (290-60)*2 = 520 pixels // 60 + (290-60)*2 = 520 pixels
// plus a couple more to be sure // plus a couple more to be sure
await tester.drag(find.text('3'), const Offset(-522.0, 0.0)); await tester.drag(find.text('3'), const Offset(-522.0, 0.0), touchSlopX: 0.0);
await tester.pump(); // just after release await tester.pump(); // just after release
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -11..279 = 4 // -11..279 = 4
@ -121,7 +121,7 @@ void main() {
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr), const Duration(seconds: 1)); await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr), const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(-280.0, 0.0)); await tester.drag(find.text('2'), const Offset(-280.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -280..10 = 0 // -280..10 = 0
@ -135,7 +135,7 @@ void main() {
expect(find.text('4'), findsNothing); expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(-290.0, 0.0)); await tester.drag(find.text('2'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -280..10 = 1 // -280..10 = 1
@ -165,7 +165,7 @@ void main() {
expect(find.text('4'), findsNothing); expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.drag(find.text('0'), const Offset(300.0, 0.0)); await tester.drag(find.text('0'), const Offset(300.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -80..210 = 3 // -80..210 = 3
@ -182,7 +182,7 @@ void main() {
// if item 3 was a bit wider, such that its center was past the 800px mark, this would fail, // if item 3 was a bit wider, such that its center was past the 800px mark, this would fail,
// because it wouldn't be hit tested when scrolling from its center, as drag() does. // because it wouldn't be hit tested when scrolling from its center, as drag() does.
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(290.0, 0.0)); await tester.drag(find.text('2'), const Offset(290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 4 // -10..280 = 4
@ -196,7 +196,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(0.0, 290.0)); await tester.drag(find.text('2'), const Offset(0.0, 290.0), touchSlopY: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// unchanged // unchanged
expect(find.text('0'), findsNothing); expect(find.text('0'), findsNothing);
@ -207,7 +207,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(290.0, 0.0)); await tester.drag(find.text('3'), const Offset(290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 5 // -10..280 = 5
@ -226,7 +226,7 @@ void main() {
// to move item 3 entirely off screen therefore takes: // to move item 3 entirely off screen therefore takes:
// 60 + (290-60)*2 = 520 pixels // 60 + (290-60)*2 = 520 pixels
// plus a couple more to be sure // plus a couple more to be sure
await tester.drag(find.text('4'), const Offset(522.0, 0.0)); await tester.drag(find.text('4'), const Offset(522.0, 0.0), touchSlopX: 0.0);
await tester.pump(); // just after release await tester.pump(); // just after release
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// 280..570 = 5 // 280..570 = 5
@ -265,7 +265,7 @@ void main() {
expect(find.text('4'), findsNothing); expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.drag(find.text('0'), const Offset(300.0, 0.0)); await tester.drag(find.text('0'), const Offset(300.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -80..210 = 3 // -80..210 = 3
@ -282,7 +282,7 @@ void main() {
// if item 3 was a bit wider, such that its center was past the 800px mark, this would fail, // if item 3 was a bit wider, such that its center was past the 800px mark, this would fail,
// because it wouldn't be hit tested when scrolling from its center, as drag() does. // because it wouldn't be hit tested when scrolling from its center, as drag() does.
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(290.0, 0.0)); await tester.drag(find.text('2'), const Offset(290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 4 // -10..280 = 4
@ -296,7 +296,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(0.0, 290.0)); await tester.drag(find.text('2'), const Offset(0.0, 290.0), touchSlopY: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// unchanged // unchanged
expect(find.text('0'), findsNothing); expect(find.text('0'), findsNothing);
@ -307,7 +307,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(290.0, 0.0)); await tester.drag(find.text('3'), const Offset(290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 5 // -10..280 = 5
@ -326,7 +326,7 @@ void main() {
// to move item 3 entirely off screen therefore takes: // to move item 3 entirely off screen therefore takes:
// 60 + (290-60)*2 = 520 pixels // 60 + (290-60)*2 = 520 pixels
// plus a couple more to be sure // plus a couple more to be sure
await tester.drag(find.text('4'), const Offset(522.0, 0.0)); await tester.drag(find.text('4'), const Offset(522.0, 0.0), touchSlopX: 0.0);
await tester.pump(); // just after release await tester.pump(); // just after release
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// 280..570 = 5 // 280..570 = 5
@ -354,7 +354,7 @@ void main() {
await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl)); await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl));
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('1'), const Offset(-300.0, 0.0)); await tester.drag(find.text('1'), const Offset(-300.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 1 // -10..280 = 1
@ -371,7 +371,7 @@ void main() {
// if item 3 was a bit wider, such that its center was past the 800px mark, this would fail, // if item 3 was a bit wider, such that its center was past the 800px mark, this would fail,
// because it wouldn't be hit tested when scrolling from its center, as drag() does. // because it wouldn't be hit tested when scrolling from its center, as drag() does.
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(-290.0, 0.0)); await tester.drag(find.text('3'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 2 // -10..280 = 2
@ -385,7 +385,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(0.0, -290.0)); await tester.drag(find.text('3'), const Offset(0.0, -290.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// unchanged // unchanged
expect(find.text('0'), findsNothing); expect(find.text('0'), findsNothing);
@ -396,7 +396,7 @@ void main() {
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('3'), const Offset(-290.0, 0.0)); await tester.drag(find.text('3'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -10..280 = 3 // -10..280 = 3
@ -415,7 +415,7 @@ void main() {
// to move item 3 entirely off screen therefore takes: // to move item 3 entirely off screen therefore takes:
// 60 + (290-60)*2 = 520 pixels // 60 + (290-60)*2 = 520 pixels
// plus a couple more to be sure // plus a couple more to be sure
await tester.drag(find.text('3'), const Offset(-522.0, 0.0)); await tester.drag(find.text('3'), const Offset(-522.0, 0.0), touchSlopX: 0.0);
await tester.pump(); // just after release await tester.pump(); // just after release
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -11..279 = 4 // -11..279 = 4
@ -440,7 +440,7 @@ void main() {
await tester.pumpWidget(Container()); await tester.pumpWidget(Container());
await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl), const Duration(seconds: 1)); await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl), const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(-280.0, 0.0)); await tester.drag(find.text('2'), const Offset(-280.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -280..10 = 0 // -280..10 = 0
@ -454,7 +454,7 @@ void main() {
expect(find.text('4'), findsNothing); expect(find.text('4'), findsNothing);
expect(find.text('5'), findsNothing); expect(find.text('5'), findsNothing);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
await tester.drag(find.text('2'), const Offset(-290.0, 0.0)); await tester.drag(find.text('2'), const Offset(-290.0, 0.0), touchSlopX: 0.0);
await tester.pump(const Duration(seconds: 1)); await tester.pump(const Duration(seconds: 1));
// screen is 800px wide, and has the following items: // screen is 800px wide, and has the following items:
// -280..10 = 1 // -280..10 = 1

View File

@ -301,7 +301,7 @@ void main() {
await tester.drag(find.byType(ListView), const Offset(0.0, -250.0)); await tester.drag(find.byType(ListView), const Offset(0.0, -250.0));
expect(log, equals(<double>[ 250.0 ])); expect(log, equals(<double>[ 20.0, 250.0 ]));
log.clear(); log.clear();
controller.dispose(); controller.dispose();

View File

@ -65,7 +65,7 @@ void main() {
testWidgets('Holding scroll', (WidgetTester tester) async { testWidgets('Holding scroll', (WidgetTester tester) async {
await pumpTest(tester, TargetPlatform.iOS); await pumpTest(tester, TargetPlatform.iOS);
await tester.drag(find.byType(Viewport), const Offset(0.0, 200.0)); await tester.drag(find.byType(Viewport), const Offset(0.0, 200.0), touchSlopY: 0.0);
expect(getScrollOffset(tester), -200.0); expect(getScrollOffset(tester), -200.0);
await tester.pump(); // trigger ballistic await tester.pump(); // trigger ballistic
await tester.pump(const Duration(milliseconds: 10)); await tester.pump(const Duration(milliseconds: 10));

View File

@ -13,6 +13,12 @@ import 'finders.dart';
import 'test_async_utils.dart'; import 'test_async_utils.dart';
import 'test_pointer.dart'; import 'test_pointer.dart';
/// The default drag touch slop used to break up a large drag into multiple
/// smaller moves.
///
/// This value must be greater than [kTouchSlop].
const double kDragSlopDefault = 20.0;
/// Class that programmatically interacts with widgets. /// Class that programmatically interacts with widgets.
/// ///
/// For a variant of this class suited specifically for unit tests, see /// For a variant of this class suited specifically for unit tests, see
@ -410,8 +416,27 @@ abstract class WidgetController {
/// ///
/// If you want the drag to end with a speed so that the gesture recognition /// If you want the drag to end with a speed so that the gesture recognition
/// system identifies the gesture as a fling, consider using [fling] instead. /// system identifies the gesture as a fling, consider using [fling] instead.
Future<void> drag(Finder finder, Offset offset, {int pointer}) { ///
return dragFrom(getCenter(finder), offset, pointer: pointer); /// {@template flutter.flutter_test.drag}
/// By default, if the x or y component of offset is greater than [kTouchSlop], the
/// gesture is broken up into two separate moves calls. Changing 'touchSlopX' or
/// `touchSlopY` will change the minimum amount of movement in the respective axis
/// before the drag will be broken into multiple calls. To always send the
/// drag with just a single call to [TestGesture.moveBy], `touchSlopX` and `touchSlopY`
/// should be set to 0.
///
/// Breaking the drag into multiple moves is necessary for accurate execution
/// of drag update calls with a [DragStartBehavior] variable set to
/// [DragStartBehavior.start]. Without such a change, the dragUpdate callback
/// from a drag recognizer will never be invoked.
///
/// To force this function to a send a single move event, the 'touchSlopX' and
/// 'touchSlopY' variables should be set to 0. However, generally, these values
/// should be left to their default values.
/// {@end template}
Future<void> drag(Finder finder, Offset offset, { int pointer, double touchSlopX = kDragSlopDefault, double touchSlopY = kDragSlopDefault }) {
assert(kDragSlopDefault > kTouchSlop);
return dragFrom(getCenter(finder), offset, pointer: pointer, touchSlopX: touchSlopX, touchSlopY: touchSlopY);
} }
/// Attempts a drag gesture consisting of a pointer down, a move by /// Attempts a drag gesture consisting of a pointer down, a move by
@ -420,11 +445,78 @@ abstract class WidgetController {
/// If you want the drag to end with a speed so that the gesture recognition /// If you want the drag to end with a speed so that the gesture recognition
/// system identifies the gesture as a fling, consider using [flingFrom] /// system identifies the gesture as a fling, consider using [flingFrom]
/// instead. /// instead.
Future<void> dragFrom(Offset startLocation, Offset offset, {int pointer}) { ///
/// {@macro flutter.flutter_test.drag}
Future<void> dragFrom(Offset startLocation, Offset offset, { int pointer, double touchSlopX = kDragSlopDefault, double touchSlopY = kDragSlopDefault }) {
assert(kDragSlopDefault > kTouchSlop);
return TestAsyncUtils.guard<void>(() async { return TestAsyncUtils.guard<void>(() async {
final TestGesture gesture = await startGesture(startLocation, pointer: pointer); final TestGesture gesture = await startGesture(startLocation, pointer: pointer);
assert(gesture != null); assert(gesture != null);
await gesture.moveBy(offset);
final double xSign = offset.dx.sign;
final double ySign = offset.dy.sign;
final double offsetX = offset.dx;
final double offsetY = offset.dy;
final bool separateX = offset.dx.abs() > touchSlopX && touchSlopX > 0;
final bool separateY = offset.dy.abs() > touchSlopY && touchSlopY > 0;
if (separateY || separateX) {
final double offsetSlope = offsetY / offsetX;
final double inverseOffsetSlope = offsetX / offsetY;
final double slopSlope = touchSlopY / touchSlopX;
final double absoluteOffsetSlope = offsetSlope.abs();
final double signedSlopX = touchSlopX * xSign;
final double signedSlopY = touchSlopY * ySign;
if (absoluteOffsetSlope != slopSlope) {
// The drag goes through one or both of the extents of the edges of the box.
if (absoluteOffsetSlope < slopSlope) {
assert(offsetX.abs() > touchSlopX);
// The drag goes through the vertical edge of the box.
// It is guaranteed that the |offsetX| > touchSlopX.
final double diffY = offsetSlope.abs() * touchSlopX * ySign;
// The vector from the origin to the vertical edge.
await gesture.moveBy(Offset(signedSlopX, diffY));
if (offsetY.abs() <= touchSlopY) {
// The drag ends on or before getting to the horizontal extension of the horizontal edge.
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY));
} else {
final double diffY2 = signedSlopY - diffY;
final double diffX2 = inverseOffsetSlope * diffY2;
// The vector from the edge of the box to the horizontal extension of the horizontal edge.
await gesture.moveBy(Offset(diffX2, diffY2));
await gesture.moveBy(Offset(offsetX - diffX2 - signedSlopX, offsetY - signedSlopY));
}
} else {
assert(offsetY.abs() > touchSlopY);
// The drag goes through the horizontal edge of the box.
// It is guaranteed that the |offsetY| > touchSlopY.
final double diffX = inverseOffsetSlope.abs() * touchSlopY * xSign;
// The vector from the origin to the vertical edge.
await gesture.moveBy(Offset(diffX, signedSlopY));
if (offsetX.abs() <= touchSlopX) {
// The drag ends on or before getting to the vertical extension of the vertical edge.
await gesture.moveBy(Offset(offsetX - diffX, offsetY - signedSlopY));
} else {
final double diffX2 = signedSlopX - diffX;
final double diffY2 = offsetSlope * diffX2;
// The vector from the edge of the box to the vertical extension of the vertical edge.
await gesture.moveBy(Offset(diffX2, diffY2));
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY2 - signedSlopY));
}
}
} else { // The drag goes through the corner of the box.
await gesture.moveBy(Offset(signedSlopX, signedSlopY));
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - signedSlopY));
}
} else { // The drag ends inside the box.
await gesture.moveBy(offset);
}
await gesture.up(); await gesture.up();
}); });
} }

View File

@ -0,0 +1,282 @@
// Copyright 2016 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:ui';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
void main() {
testWidgets(
'WidgetTester.drag must break the offset into multiple parallel components if'
'the drag goes outside the touch slop values',
(WidgetTester tester) async {
// The first Offset in every sub array (ie. offsetResults[i][0]) is (touchSlopX, touchSlopY).
// The second Offset in every sub array (ie. offsetResults[i][1]) will be the total move offset.
// The remaining values in every sub array are the expected separated drag offsets.
// This test checks to make sure that the total drag will be correctly split into
// pieces such that the first (and potentially second) moveBy function call(s) in
// controller.drag() will never have a component greater than the touch
// slop in that component's respective axis.
final List<List<Offset>> offsetResults = <List<Offset>>[
<Offset>[
const Offset(10.0, 10.0),
const Offset(-150.0, 200.0),
const Offset(-7.5, 10.0),
const Offset(-2.5, 3.333333333333333),
const Offset(-140.0, 186.66666666666666),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(150, -200),
const Offset(7.5, -10),
const Offset(2.5, -3.333333333333333),
const Offset(140.0, -186.66666666666666),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(-200, 150),
const Offset(-10, 7.5),
const Offset(-3.333333333333333, 2.5),
const Offset(-186.66666666666666, 140.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(200.0, -150.0),
const Offset(10, -7.5),
const Offset(3.333333333333333, -2.5),
const Offset(186.66666666666666, -140.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(-150.0, -200.0),
const Offset(-7.5, -10.0),
const Offset(-2.5, -3.333333333333333),
const Offset(-140.0, -186.66666666666666),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(8.0, 3.0),
const Offset(8.0, 3.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(3.0, 8.0),
const Offset(3.0, 8.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(20.0, 5.0),
const Offset(10.0, 2.5),
const Offset(10.0, 2.5),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(5.0, 20.0),
const Offset(2.5, 10.0),
const Offset(2.5, 10.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(20.0, 15.0),
const Offset(10.0, 7.5),
const Offset(3.333333333333333, 2.5),
const Offset(6.666666666666668, 5.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(15.0, 20.0),
const Offset(7.5, 10.0),
const Offset(2.5, 3.333333333333333),
const Offset(5.0, 6.666666666666668),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(20.0, 20.0),
const Offset(10.0, 10.0),
const Offset(10.0, 10.0),
],
<Offset>[
const Offset(10.0, 10.0),
const Offset(0.0, 5.0),
const Offset(0.0, 5.0),
],
//// [VARYING TOUCH SLOP] ////
<Offset>[
const Offset(12.0, 5.0),
const Offset(0.0, 5.0),
const Offset(0.0, 5.0),
],
<Offset>[
const Offset(12.0, 5.0),
const Offset(20.0, 5.0),
const Offset(12.0, 3.0),
const Offset(8.0, 2.0),
],
<Offset>[
const Offset(12.0, 5.0),
const Offset(5.0, 20.0),
const Offset(1.25, 5.0),
const Offset(3.75, 15.0),
],
<Offset>[
const Offset(5.0, 12.0),
const Offset(5.0, 20.0),
const Offset(3.0, 12.0),
const Offset(2.0, 8.0),
],
<Offset>[
const Offset(5.0, 12.0),
const Offset(20.0, 5.0),
const Offset(5.0, 1.25),
const Offset(15.0, 3.75),
],
<Offset>[
const Offset(18.0, 18.0),
const Offset(0.0, 150.0),
const Offset(0.0, 18.0),
const Offset(0.0, 132.0),
],
<Offset>[
const Offset(18.0, 18.0),
const Offset(0.0, -150.0),
const Offset(0.0, -18.0),
const Offset(0.0, -132.0),
],
<Offset>[
const Offset(18.0, 18.0),
const Offset(-150.0, 0.0),
const Offset(-18.0, 0.0),
const Offset(-132.0, 0.0),
],
<Offset>[
const Offset(0.0, 0.0),
const Offset(-150.0, 0.0),
const Offset(-150.0, 0.0),
],
<Offset>[
const Offset(18.0, 18.0),
const Offset(-32.0, 0.0),
const Offset(-18.0, 0.0),
const Offset(-14.0, 0.0),
],
];
await tester.pumpWidget(
const Directionality(
textDirection: TextDirection.ltr,
child: Text('test'),
),
);
final WidgetControllerSpy spyController = WidgetControllerSpy(tester.binding);
for (int resultIndex = 0; resultIndex < offsetResults.length; resultIndex += 1) {
final List<Offset> testResult = offsetResults[resultIndex];
await spyController.drag(
find.text('test'),
testResult[1],
touchSlopX: testResult[0].dx,
touchSlopY: testResult[0].dy,
);
final List<Offset> dragOffsets = spyController.testGestureSpy.offsets;
expect(
offsetResults[resultIndex].length - 2,
dragOffsets.length,
reason:
'There is a difference in the number of expected and actual split offsets for the drag with:\n'
'Touch Slop: ' + testResult[0].toString() + '\n'
'Delta: ' + testResult[1].toString() + '\n',
);
for (int valueIndex = 2; valueIndex < offsetResults[resultIndex].length; valueIndex += 1) {
expect(
offsetResults[resultIndex][valueIndex],
dragOffsets[valueIndex - 2],
reason:
'There is a difference in the expected and actual value of the ' +
(valueIndex == 2 ? 'first' : valueIndex == 3 ? 'second' : 'third') +
' split offset for the drag with:\n'
'Touch slop: ' + testResult[0].toString() + '\n'
'Delta: ' + testResult[1].toString() + '\n',
);
}
spyController.testGestureSpy.clearOffsets();
}
},
);
}
class WidgetControllerSpy extends WidgetController {
WidgetControllerSpy(
TestWidgetsFlutterBinding binding
) : super(binding) {
_binding = binding;
}
TestWidgetsFlutterBinding _binding;
@override
Future<void> pump(Duration duration) async {
if (duration != null)
await Future<void>.delayed(duration);
_binding.scheduleFrame();
await _binding.endOfFrame;
}
int _getNextPointer() {
final int result = nextPointer;
nextPointer += 1;
return result;
}
@override
Future<void> sendEventToBinding(PointerEvent event, HitTestResult result) {
return TestAsyncUtils.guard<void>(() async {
_binding.dispatchEvent(event, result, source: TestBindingEventSource.test);
});
}
TestGestureSpy testGestureSpy;
@override
Future<TestGesture> createGesture({int pointer, PointerDeviceKind kind = PointerDeviceKind.touch}) async {
return testGestureSpy = TestGestureSpy(
pointer: pointer ?? _getNextPointer(),
kind: kind,
dispatcher: sendEventToBinding,
hitTester: hitTestOnBinding
);
}
}
class TestGestureSpy extends TestGesture {
TestGestureSpy({
int pointer,
PointerDeviceKind kind,
EventDispatcher dispatcher,
HitTester hitTester
}) : super(
pointer: pointer,
kind: kind,
dispatcher: dispatcher,
hitTester: hitTester
);
List<Offset> offsets = <Offset>[];
void clearOffsets() {
offsets = <Offset>[];
}
@override
Future<void> moveBy(Offset offset, {Duration timeStamp = Duration.zero}) {
offsets.add(offset);
return super.moveBy(offset, timeStamp: timeStamp);
}
}