mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
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:
parent
62e55a45d4
commit
47724f97fa
@ -60,7 +60,7 @@ class CupertinoSwitch extends StatefulWidget {
|
||||
@required this.value,
|
||||
@required this.onChanged,
|
||||
this.activeColor,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(dragStartBehavior != null),
|
||||
super(key: key);
|
||||
|
||||
@ -97,7 +97,6 @@ class CupertinoSwitch extends StatefulWidget {
|
||||
/// [CupertinoTheme] in accordance to native iOS behavior.
|
||||
final Color activeColor;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// {@template flutter.cupertino.switch.dragStartBehavior}
|
||||
/// 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
|
||||
/// 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:
|
||||
///
|
||||
@ -149,7 +148,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
this.activeColor,
|
||||
this.onChanged,
|
||||
this.vsync,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : super(key: key);
|
||||
|
||||
final bool value;
|
||||
@ -202,7 +201,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox {
|
||||
ValueChanged<bool> onChanged,
|
||||
@required TextDirection textDirection,
|
||||
@required TickerProvider vsync,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(value != null),
|
||||
assert(activeColor != null),
|
||||
assert(vsync != null),
|
||||
|
@ -54,6 +54,10 @@ const Duration kZoomControlsTimeout = Duration(milliseconds: 3000);
|
||||
/// 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
|
||||
/// 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
|
||||
// 18.0 after getting complaints that it was too difficult to hit targets.
|
||||
const double kTouchSlop = 18.0; // Logical pixels
|
||||
|
@ -54,7 +54,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
|
||||
/// [dragStartBehavior] must not be null.
|
||||
DragGestureRecognizer({
|
||||
Object debugOwner,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(dragStartBehavior != null),
|
||||
super(debugOwner: debugOwner);
|
||||
|
||||
|
@ -254,7 +254,7 @@ class DayPicker extends StatelessWidget {
|
||||
@required this.lastDate,
|
||||
@required this.displayedMonth,
|
||||
this.selectableDayPredicate,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(selectedDate != null),
|
||||
assert(currentDate != null),
|
||||
assert(onChanged != null),
|
||||
@ -287,7 +287,6 @@ class DayPicker extends StatelessWidget {
|
||||
/// Optional user supplied predicate function to customize selectable days.
|
||||
final SelectableDayPredicate selectableDayPredicate;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// Determines the way that drag start behavior is handled.
|
||||
///
|
||||
/// 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
|
||||
/// 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:
|
||||
///
|
||||
@ -528,7 +527,7 @@ class MonthPicker extends StatefulWidget {
|
||||
@required this.firstDate,
|
||||
@required this.lastDate,
|
||||
this.selectableDayPredicate,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(selectedDate != null),
|
||||
assert(onChanged != null),
|
||||
assert(!firstDate.isAfter(lastDate)),
|
||||
@ -791,7 +790,7 @@ class YearPicker extends StatefulWidget {
|
||||
@required this.onChanged,
|
||||
@required this.firstDate,
|
||||
@required this.lastDate,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(selectedDate != null),
|
||||
assert(onChanged != null),
|
||||
assert(!firstDate.isAfter(lastDate)),
|
||||
|
@ -180,7 +180,7 @@ class DrawerController extends StatefulWidget {
|
||||
@required this.child,
|
||||
@required this.alignment,
|
||||
this.drawerCallback,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(child != null),
|
||||
assert(dragStartBehavior != null),
|
||||
assert(alignment != null),
|
||||
@ -200,7 +200,6 @@ class DrawerController extends StatefulWidget {
|
||||
/// Optional callback that is called when a [Drawer] is opened or closed.
|
||||
final DrawerCallback drawerCallback;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// {@template flutter.material.drawer.dragStartBehavior}
|
||||
/// 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
|
||||
/// 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:
|
||||
///
|
||||
|
@ -75,7 +75,7 @@ class PaginatedDataTable extends StatefulWidget {
|
||||
this.rowsPerPage = defaultRowsPerPage,
|
||||
this.availableRowsPerPage = const <int>[defaultRowsPerPage, defaultRowsPerPage * 2, defaultRowsPerPage * 5, defaultRowsPerPage * 10],
|
||||
this.onRowsPerPageChanged,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
@required this.source
|
||||
}) : assert(header != null),
|
||||
assert(columns != null),
|
||||
|
@ -876,8 +876,8 @@ class Scaffold extends StatefulWidget {
|
||||
this.resizeToAvoidBottomPadding,
|
||||
this.resizeToAvoidBottomInset,
|
||||
this.primary = true,
|
||||
this.drawerDragStartBehavior = DragStartBehavior.start,
|
||||
this.extendBody = false,
|
||||
this.drawerDragStartBehavior = DragStartBehavior.down,
|
||||
}) : assert(primary != null),
|
||||
assert(extendBody != null),
|
||||
assert(drawerDragStartBehavior != null),
|
||||
|
@ -73,7 +73,7 @@ class Switch extends StatefulWidget {
|
||||
this.activeThumbImage,
|
||||
this.inactiveThumbImage,
|
||||
this.materialTapTargetSize,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : _switchType = _SwitchType.material,
|
||||
assert(dragStartBehavior != null),
|
||||
super(key: key);
|
||||
@ -97,7 +97,7 @@ class Switch extends StatefulWidget {
|
||||
this.activeThumbImage,
|
||||
this.inactiveThumbImage,
|
||||
this.materialTapTargetSize,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : _switchType = _SwitchType.adaptive,
|
||||
super(key: key);
|
||||
|
||||
|
@ -562,7 +562,7 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.labelPadding,
|
||||
this.unselectedLabelColor,
|
||||
this.unselectedLabelStyle,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
this.onTap,
|
||||
}) : assert(tabs != null),
|
||||
assert(isScrollable != null),
|
||||
@ -1057,7 +1057,7 @@ class TabBarView extends StatefulWidget {
|
||||
@required this.children,
|
||||
this.controller,
|
||||
this.physics,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(children != null),
|
||||
assert(dragStartBehavior != null),
|
||||
super(key: key);
|
||||
|
@ -143,7 +143,7 @@ class TextField extends StatefulWidget {
|
||||
this.cursorColor,
|
||||
this.keyboardAppearance,
|
||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
this.enableInteractiveSelection,
|
||||
this.onTap,
|
||||
this.buildCounter,
|
||||
|
@ -91,7 +91,7 @@ class Dismissible extends StatefulWidget {
|
||||
this.dismissThresholds = const <DismissDirection, double>{},
|
||||
this.movementDuration = const Duration(milliseconds: 200),
|
||||
this.crossAxisEndOffset = 0.0,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(key != null),
|
||||
assert(secondaryBackground != null ? background != null : true),
|
||||
assert(dragStartBehavior != null),
|
||||
@ -162,7 +162,6 @@ class Dismissible extends StatefulWidget {
|
||||
/// it is positive or negative.
|
||||
final double crossAxisEndOffset;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// Determines the way that drag start behavior is handled.
|
||||
///
|
||||
/// 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
|
||||
/// 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:
|
||||
///
|
||||
|
@ -231,7 +231,7 @@ class EditableText extends StatefulWidget {
|
||||
this.paintCursorAboveText = false,
|
||||
this.scrollPadding = const EdgeInsets.all(20.0),
|
||||
this.keyboardAppearance = Brightness.light,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
this.enableInteractiveSelection,
|
||||
}) : assert(controller != null),
|
||||
assert(focusNode != null),
|
||||
|
@ -186,7 +186,7 @@ class GestureDetector extends StatelessWidget {
|
||||
this.onScaleEnd,
|
||||
this.behavior,
|
||||
this.excludeFromSemantics = false,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(excludeFromSemantics != null),
|
||||
assert(dragStartBehavior != null),
|
||||
assert(() {
|
||||
@ -373,7 +373,6 @@ class GestureDetector extends StatelessWidget {
|
||||
/// duplication of information.
|
||||
final bool excludeFromSemantics;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// Determines the way that drag start behavior is handled.
|
||||
///
|
||||
/// 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
|
||||
/// 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],
|
||||
/// [HorizontalDragGestureRecognizer] and [PanGestureRecognizer] are affected
|
||||
|
@ -189,7 +189,7 @@ class NestedScrollView extends StatefulWidget {
|
||||
this.physics,
|
||||
@required this.headerSliverBuilder,
|
||||
@required this.body,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(scrollDirection != null),
|
||||
assert(reverse != null),
|
||||
assert(headerSliverBuilder != null),
|
||||
@ -371,7 +371,7 @@ class _NestedScrollViewCustomScrollView extends CustomScrollView {
|
||||
@required ScrollController controller,
|
||||
@required List<Widget> slivers,
|
||||
@required this.handle,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : super(
|
||||
scrollDirection: scrollDirection,
|
||||
reverse: reverse,
|
||||
|
@ -425,7 +425,7 @@ class PageView extends StatefulWidget {
|
||||
this.pageSnapping = true,
|
||||
this.onPageChanged,
|
||||
List<Widget> children = const <Widget>[],
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : controller = controller ?? _defaultPageController,
|
||||
childrenDelegate = SliverChildListDelegate(children),
|
||||
super(key: key);
|
||||
@ -452,7 +452,7 @@ class PageView extends StatefulWidget {
|
||||
this.onPageChanged,
|
||||
@required IndexedWidgetBuilder itemBuilder,
|
||||
int itemCount,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : controller = controller ?? _defaultPageController,
|
||||
childrenDelegate = SliverChildBuilderDelegate(itemBuilder, childCount: itemCount),
|
||||
super(key: key);
|
||||
@ -468,7 +468,7 @@ class PageView extends StatefulWidget {
|
||||
this.pageSnapping = true,
|
||||
this.onPageChanged,
|
||||
@required this.childrenDelegate,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(childrenDelegate != null),
|
||||
controller = controller ?? _defaultPageController,
|
||||
super(key: key);
|
||||
|
@ -312,7 +312,6 @@ class ScrollDragController implements Drag {
|
||||
// May be null for proxied drags like via accessibility.
|
||||
return offset;
|
||||
}
|
||||
|
||||
if (offset == 0.0) {
|
||||
if (motionStartDistanceThreshold != null &&
|
||||
_offsetSinceLastStop == null &&
|
||||
|
@ -69,7 +69,7 @@ abstract class ScrollView extends StatelessWidget {
|
||||
this.anchor = 0.0,
|
||||
this.cacheExtent,
|
||||
this.semanticChildCount,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(scrollDirection != null),
|
||||
assert(reverse != null),
|
||||
assert(shrinkWrap != null),
|
||||
@ -454,7 +454,7 @@ class CustomScrollView extends ScrollView {
|
||||
double cacheExtent,
|
||||
this.slivers = const <Widget>[],
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : super(
|
||||
key: key,
|
||||
scrollDirection: scrollDirection,
|
||||
@ -500,7 +500,7 @@ abstract class BoxScrollView extends ScrollView {
|
||||
this.padding,
|
||||
double cacheExtent,
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : super(
|
||||
key: key,
|
||||
scrollDirection: scrollDirection,
|
||||
@ -802,7 +802,7 @@ class ListView extends BoxScrollView {
|
||||
double cacheExtent,
|
||||
List<Widget> children = const <Widget>[],
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : childrenDelegate = SliverChildListDelegate(
|
||||
children,
|
||||
addAutomaticKeepAlives: addAutomaticKeepAlives,
|
||||
@ -866,7 +866,7 @@ class ListView extends BoxScrollView {
|
||||
bool addSemanticIndexes = true,
|
||||
double cacheExtent,
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : childrenDelegate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
@ -1320,7 +1320,7 @@ class GridView extends BoxScrollView {
|
||||
@required this.childrenDelegate,
|
||||
double cacheExtent,
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(gridDelegate != null),
|
||||
assert(childrenDelegate != null),
|
||||
super(
|
||||
@ -1370,7 +1370,7 @@ class GridView extends BoxScrollView {
|
||||
double cacheExtent,
|
||||
List<Widget> children = const <Widget>[],
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: crossAxisCount,
|
||||
mainAxisSpacing: mainAxisSpacing,
|
||||
@ -1429,7 +1429,7 @@ class GridView extends BoxScrollView {
|
||||
bool addSemanticIndexes = true,
|
||||
List<Widget> children = const <Widget>[],
|
||||
int semanticChildCount,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.down,
|
||||
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
|
||||
}) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: maxCrossAxisExtent,
|
||||
mainAxisSpacing: mainAxisSpacing,
|
||||
|
@ -81,7 +81,7 @@ class Scrollable extends StatefulWidget {
|
||||
@required this.viewportBuilder,
|
||||
this.excludeFromSemantics = false,
|
||||
this.semanticChildCount,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(axisDirection != null),
|
||||
assert(dragStartBehavior != null),
|
||||
assert(viewportBuilder != null),
|
||||
@ -194,7 +194,7 @@ class Scrollable extends StatefulWidget {
|
||||
/// animation smoother and setting it to [DragStartBehavior.down] will make
|
||||
/// 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:
|
||||
///
|
||||
|
@ -204,7 +204,7 @@ class SingleChildScrollView extends StatelessWidget {
|
||||
this.physics,
|
||||
this.controller,
|
||||
this.child,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(scrollDirection != null),
|
||||
assert(dragStartBehavior != null),
|
||||
assert(!(controller != null && primary == true),
|
||||
|
@ -230,7 +230,7 @@ class TextSelectionOverlay {
|
||||
@required this.renderObject,
|
||||
this.selectionControls,
|
||||
this.selectionDelegate,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : assert(value != null),
|
||||
assert(context != null),
|
||||
_value = value {
|
||||
@ -265,7 +265,6 @@ class TextSelectionOverlay {
|
||||
/// text field.
|
||||
final TextSelectionDelegate selectionDelegate;
|
||||
|
||||
// TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets.
|
||||
/// Determines the way that drag start behavior is handled.
|
||||
///
|
||||
/// 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
|
||||
/// 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:
|
||||
///
|
||||
@ -468,7 +467,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
|
||||
@required this.onSelectionHandleChanged,
|
||||
@required this.onSelectionHandleTapped,
|
||||
@required this.selectionControls,
|
||||
this.dragStartBehavior = DragStartBehavior.down,
|
||||
this.dragStartBehavior = DragStartBehavior.start,
|
||||
}) : super(key: key);
|
||||
|
||||
final TextSelection selection;
|
||||
|
@ -8,7 +8,7 @@ import 'package:flutter/semantics.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
// 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() {
|
||||
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(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(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.
|
||||
expect(
|
||||
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();
|
||||
expect(
|
||||
date,
|
||||
DateTime(2018, 2, 28),
|
||||
);
|
||||
|
||||
|
||||
await tester.drag(find.text('28'), const Offset(0.0, -32.0));
|
||||
await tester.drag(find.text('28'), const Offset(0.0, -32.0), touchSlopY: 0.0);
|
||||
await tester.pump(); // Once to trigger the post frame animate call.
|
||||
|
||||
// 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
|
||||
await tester.drag(find.text('11'), _kRowOffset);
|
||||
await tester.pump();
|
||||
@ -721,14 +723,14 @@ void main() {
|
||||
expect(date, DateTime(2018, 1, 1, 11, 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(const Duration(milliseconds: 500));
|
||||
|
||||
expect(date, DateTime(2018, 1, 1, 9, 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(const Duration(milliseconds: 500));
|
||||
|
||||
|
@ -298,7 +298,7 @@ void main() {
|
||||
);
|
||||
|
||||
// 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.
|
||||
expect(
|
||||
@ -315,7 +315,7 @@ void main() {
|
||||
expect(selectedItems.isEmpty, true);
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -117,7 +117,7 @@ void main() {
|
||||
);
|
||||
|
||||
// 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();
|
||||
|
||||
// The function is referenced once while passing into CupertinoSliverRefreshControl
|
||||
@ -191,7 +191,7 @@ void main() {
|
||||
);
|
||||
|
||||
// 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(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();
|
||||
// Let it start snapping back.
|
||||
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();
|
||||
|
||||
verify(mockHelper.builder(
|
||||
@ -411,7 +411,7 @@ void main() {
|
||||
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();
|
||||
|
||||
// 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();
|
||||
verify(mockHelper.builder(
|
||||
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();
|
||||
verify(mockHelper.builder(
|
||||
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();
|
||||
verify(mockHelper.refreshTask());
|
||||
|
||||
@ -670,7 +670,7 @@ void main() {
|
||||
|
||||
// Start another drag by an amount that would have been enough to
|
||||
// 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();
|
||||
|
||||
// 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.
|
||||
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();
|
||||
verify(mockHelper.builder(
|
||||
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();
|
||||
verify(mockHelper.builder(
|
||||
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();
|
||||
expect(
|
||||
CupertinoSliverRefreshControl.state(tester.element(find.byType(LayoutBuilder))),
|
||||
|
@ -255,7 +255,6 @@ void main() {
|
||||
return Center(
|
||||
child: CupertinoSwitch(
|
||||
value: value,
|
||||
dragStartBehavior: DragStartBehavior.down,
|
||||
onChanged: (bool newValue) {
|
||||
setState(() {
|
||||
value = newValue;
|
||||
@ -270,21 +269,21 @@ void main() {
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
});
|
||||
|
@ -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
|
||||
expect(didStartPan, isTrue); // 22 > 18
|
||||
didStartPan = false;
|
||||
// TODO(jslavitz): revert this testing change.
|
||||
expect(updatedScrollDelta, const Offset(10.0, 20.0));
|
||||
updatedScrollDelta = null;
|
||||
expect(didEndPan, isFalse);
|
||||
expect(didTap, isFalse);
|
||||
|
||||
@ -82,6 +79,58 @@ void main() {
|
||||
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) {
|
||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||
|
||||
|
@ -102,7 +102,7 @@ void main() {
|
||||
didStartPan = true;
|
||||
},
|
||||
onPanUpdate: (DragUpdateDetails details) {
|
||||
panDelta = details.delta;
|
||||
panDelta = panDelta == null ? details.delta : panDelta + details.delta;
|
||||
},
|
||||
onPanEnd: (DragEndDetails details) {
|
||||
didEndPan = true;
|
||||
|
@ -35,7 +35,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(textDirection: TextDirection.ltr));
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -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,
|
||||
// because it wouldn't be hit tested when scrolling from its center, as drag() does.
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 2
|
||||
@ -66,7 +66,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// unchanged
|
||||
expect(find.text('0'), findsNothing);
|
||||
@ -77,7 +77,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 3
|
||||
@ -96,7 +96,7 @@ void main() {
|
||||
// to move item 3 entirely off screen therefore takes:
|
||||
// 60 + (290-60)*2 = 520 pixels
|
||||
// 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
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -11..279 = 4
|
||||
@ -121,7 +121,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -280..10 = 0
|
||||
@ -135,7 +135,7 @@ void main() {
|
||||
expect(find.text('4'), findsNothing);
|
||||
expect(find.text('5'), findsNothing);
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -280..10 = 1
|
||||
@ -165,7 +165,7 @@ void main() {
|
||||
expect(find.text('4'), 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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -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,
|
||||
// because it wouldn't be hit tested when scrolling from its center, as drag() does.
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 4
|
||||
@ -196,7 +196,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// unchanged
|
||||
expect(find.text('0'), findsNothing);
|
||||
@ -207,7 +207,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 5
|
||||
@ -226,7 +226,7 @@ void main() {
|
||||
// to move item 3 entirely off screen therefore takes:
|
||||
// 60 + (290-60)*2 = 520 pixels
|
||||
// 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
|
||||
// screen is 800px wide, and has the following items:
|
||||
// 280..570 = 5
|
||||
@ -265,7 +265,7 @@ void main() {
|
||||
expect(find.text('4'), 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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -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,
|
||||
// because it wouldn't be hit tested when scrolling from its center, as drag() does.
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 4
|
||||
@ -296,7 +296,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// unchanged
|
||||
expect(find.text('0'), findsNothing);
|
||||
@ -307,7 +307,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 5
|
||||
@ -326,7 +326,7 @@ void main() {
|
||||
// to move item 3 entirely off screen therefore takes:
|
||||
// 60 + (290-60)*2 = 520 pixels
|
||||
// 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
|
||||
// screen is 800px wide, and has the following items:
|
||||
// 280..570 = 5
|
||||
@ -354,7 +354,7 @@ void main() {
|
||||
await tester.pumpWidget(buildFrame(reverse: true, textDirection: TextDirection.rtl));
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -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,
|
||||
// because it wouldn't be hit tested when scrolling from its center, as drag() does.
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 2
|
||||
@ -385,7 +385,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// unchanged
|
||||
expect(find.text('0'), findsNothing);
|
||||
@ -396,7 +396,7 @@ void main() {
|
||||
expect(find.text('5'), findsNothing);
|
||||
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -10..280 = 3
|
||||
@ -415,7 +415,7 @@ void main() {
|
||||
// to move item 3 entirely off screen therefore takes:
|
||||
// 60 + (290-60)*2 = 520 pixels
|
||||
// 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
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -11..279 = 4
|
||||
@ -440,7 +440,7 @@ void main() {
|
||||
|
||||
await tester.pumpWidget(Container());
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -280..10 = 0
|
||||
@ -454,7 +454,7 @@ void main() {
|
||||
expect(find.text('4'), findsNothing);
|
||||
expect(find.text('5'), findsNothing);
|
||||
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));
|
||||
// screen is 800px wide, and has the following items:
|
||||
// -280..10 = 1
|
||||
|
@ -301,7 +301,7 @@ void main() {
|
||||
|
||||
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();
|
||||
|
||||
controller.dispose();
|
||||
|
@ -65,7 +65,7 @@ void main() {
|
||||
|
||||
testWidgets('Holding scroll', (WidgetTester tester) async {
|
||||
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);
|
||||
await tester.pump(); // trigger ballistic
|
||||
await tester.pump(const Duration(milliseconds: 10));
|
||||
|
@ -13,6 +13,12 @@ import 'finders.dart';
|
||||
import 'test_async_utils.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.
|
||||
///
|
||||
/// 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
|
||||
/// 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
|
||||
@ -420,11 +445,78 @@ abstract class WidgetController {
|
||||
/// 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]
|
||||
/// 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 {
|
||||
final TestGesture gesture = await startGesture(startLocation, pointer: pointer);
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
282
packages/flutter_test/test/controller_test.dart
Normal file
282
packages/flutter_test/test/controller_test.dart
Normal 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user