Unverified Commit 08538f91 authored by jslavitz's avatar jslavitz Committed by GitHub

Teach drag start behaviors to DragGestureRecognizer (#23424)

* Adds start behavior option to the drag gesture recognizer and makes it the default option when a drag gesture recognizer is created. Also fixes all the tests to work correctly with the new default behavior.
parent 868ff428
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../../gallery/demo.dart'; import '../../gallery/demo.dart';
...@@ -79,6 +80,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin { ...@@ -79,6 +80,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
key: _scaffoldKey, key: _scaffoldKey,
appBar: AppBar( appBar: AppBar(
leading: IconButton( leading: IconButton(
...@@ -106,6 +108,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin { ...@@ -106,6 +108,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
), ),
otherAccountsPictures: <Widget>[ otherAccountsPictures: <Widget>[
GestureDetector( GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
_onOtherAccountsTap(context); _onOtherAccountsTap(context);
}, },
...@@ -120,6 +123,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin { ...@@ -120,6 +123,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
), ),
), ),
GestureDetector( GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
_onOtherAccountsTap(context); _onOtherAccountsTap(context);
}, },
...@@ -149,6 +153,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin { ...@@ -149,6 +153,7 @@ class _DrawerDemoState extends State<DrawerDemo> with TickerProviderStateMixin {
removeTop: true, removeTop: true,
child: Expanded( child: Expanded(
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
padding: const EdgeInsets.only(top: 8.0), padding: const EdgeInsets.only(top: 8.0),
children: <Widget>[ children: <Widget>[
Stack( Stack(
......
...@@ -6,6 +6,7 @@ import 'dart:async'; ...@@ -6,6 +6,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../../gallery/demo.dart'; import '../../gallery/demo.dart';
...@@ -67,6 +68,7 @@ class _PasswordFieldState extends State<PasswordField> { ...@@ -67,6 +68,7 @@ class _PasswordFieldState extends State<PasswordField> {
labelText: widget.labelText, labelText: widget.labelText,
helperText: widget.helperText, helperText: widget.helperText,
suffixIcon: GestureDetector( suffixIcon: GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
setState(() { setState(() {
_obscureText = !_obscureText; _obscureText = !_obscureText;
...@@ -167,6 +169,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -167,6 +169,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
key: _scaffoldKey, key: _scaffoldKey,
appBar: AppBar( appBar: AppBar(
title: const Text('Text fields'), title: const Text('Text fields'),
...@@ -180,6 +183,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> { ...@@ -180,6 +183,7 @@ class TextFormFieldDemoState extends State<TextFormFieldDemo> {
autovalidate: _autovalidate, autovalidate: _autovalidate,
onWillPop: _warnUserAboutInvalidData, onWillPop: _warnUserAboutInvalidData,
child: SingleChildScrollView( child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show debugDumpRenderTree, debugDumpLayerTree, debugDumpSemanticsTree, DebugSemanticsDumpOrder; import 'package:flutter/rendering.dart' show debugDumpRenderTree, debugDumpLayerTree, debugDumpSemanticsTree, DebugSemanticsDumpOrder;
import 'package:flutter/scheduler.dart' show timeDilation; import 'package:flutter/scheduler.dart' show timeDilation;
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'stock_data.dart'; import 'stock_data.dart';
import 'stock_list.dart'; import 'stock_list.dart';
import 'stock_strings.dart'; import 'stock_strings.dart';
...@@ -110,6 +111,7 @@ class StockHomeState extends State<StockHome> { ...@@ -110,6 +111,7 @@ class StockHomeState extends State<StockHome> {
Widget _buildDrawer(BuildContext context) { Widget _buildDrawer(BuildContext context) {
return Drawer( return Drawer(
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
const DrawerHeader(child: Center(child: Text('Stocks'))), const DrawerHeader(child: Center(child: Text('Stocks'))),
const ListTile( const ListTile(
...@@ -317,11 +319,13 @@ class StockHomeState extends State<StockHome> { ...@@ -317,11 +319,13 @@ class StockHomeState extends State<StockHome> {
return DefaultTabController( return DefaultTabController(
length: 2, length: 2,
child: Scaffold( child: Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
key: _scaffoldKey, key: _scaffoldKey,
appBar: _isSearching ? buildSearchBar() : buildAppBar(), appBar: _isSearching ? buildSearchBar() : buildAppBar(),
floatingActionButton: buildFloatingActionButton(), floatingActionButton: buildFloatingActionButton(),
drawer: _buildDrawer(context), drawer: _buildDrawer(context),
body: TabBarView( body: TabBarView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
_buildStockTab(context, StockHomeTab.market, widget.stocks.allSymbols), _buildStockTab(context, StockHomeTab.market, widget.stocks.allSymbols),
_buildStockTab(context, StockHomeTab.portfolio, portfolioSymbols), _buildStockTab(context, StockHomeTab.portfolio, portfolioSymbols),
......
...@@ -52,12 +52,16 @@ import 'thumb_painter.dart'; ...@@ -52,12 +52,16 @@ import 'thumb_painter.dart';
/// * <https://developer.apple.com/ios/human-interface-guidelines/controls/switches/> /// * <https://developer.apple.com/ios/human-interface-guidelines/controls/switches/>
class CupertinoSwitch extends StatefulWidget { class CupertinoSwitch extends StatefulWidget {
/// Creates an iOS-style switch. /// Creates an iOS-style switch.
///
/// [dragStartBehavior] must not be null.
const CupertinoSwitch({ const CupertinoSwitch({
Key key, Key key,
@required this.value, @required this.value,
@required this.onChanged, @required this.onChanged,
this.activeColor, this.activeColor,
}) : super(key: key); this.dragStartBehavior = DragStartBehavior.start,
}) : assert(dragStartBehavior != null),
super(key: key);
/// Whether this switch is on or off. /// Whether this switch is on or off.
final bool value; final bool value;
...@@ -92,6 +96,26 @@ class CupertinoSwitch extends StatefulWidget { ...@@ -92,6 +96,26 @@ class CupertinoSwitch extends StatefulWidget {
/// [CupertinoTheme] in accordance to native iOS behavior. /// [CupertinoTheme] in accordance to native iOS behavior.
final Color activeColor; final Color activeColor;
/// {@template flutter.cupertino.switch.dragStartBehavior}
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], the drag behavior used to move the
/// switch from on to off will begin upon the detection of a drag gesture. If
/// set to [DragStartBehavior.down] it will begin when a down event is first
/// detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
/// {@endtemplate}
final DragStartBehavior dragStartBehavior;
@override @override
_CupertinoSwitchState createState() => _CupertinoSwitchState(); _CupertinoSwitchState createState() => _CupertinoSwitchState();
...@@ -111,6 +135,7 @@ class _CupertinoSwitchState extends State<CupertinoSwitch> with TickerProviderSt ...@@ -111,6 +135,7 @@ class _CupertinoSwitchState extends State<CupertinoSwitch> with TickerProviderSt
activeColor: widget.activeColor ?? CupertinoColors.activeGreen, activeColor: widget.activeColor ?? CupertinoColors.activeGreen,
onChanged: widget.onChanged, onChanged: widget.onChanged,
vsync: this, vsync: this,
dragStartBehavior: widget.dragStartBehavior,
); );
} }
} }
...@@ -122,12 +147,14 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -122,12 +147,14 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
this.activeColor, this.activeColor,
this.onChanged, this.onChanged,
this.vsync, this.vsync,
this.dragStartBehavior = DragStartBehavior.start,
}) : super(key: key); }) : super(key: key);
final bool value; final bool value;
final Color activeColor; final Color activeColor;
final ValueChanged<bool> onChanged; final ValueChanged<bool> onChanged;
final TickerProvider vsync; final TickerProvider vsync;
final DragStartBehavior dragStartBehavior;
@override @override
_RenderCupertinoSwitch createRenderObject(BuildContext context) { _RenderCupertinoSwitch createRenderObject(BuildContext context) {
...@@ -137,6 +164,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -137,6 +164,7 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
onChanged: onChanged, onChanged: onChanged,
textDirection: Directionality.of(context), textDirection: Directionality.of(context),
vsync: vsync, vsync: vsync,
dragStartBehavior: dragStartBehavior
); );
} }
...@@ -147,7 +175,8 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -147,7 +175,8 @@ class _CupertinoSwitchRenderObjectWidget extends LeafRenderObjectWidget {
..activeColor = activeColor ..activeColor = activeColor
..onChanged = onChanged ..onChanged = onChanged
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
..vsync = vsync; ..vsync = vsync
..dragStartBehavior = dragStartBehavior;
} }
} }
...@@ -171,6 +200,7 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { ...@@ -171,6 +200,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.start,
}) : assert(value != null), }) : assert(value != null),
assert(activeColor != null), assert(activeColor != null),
assert(vsync != null), assert(vsync != null),
...@@ -188,7 +218,8 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { ...@@ -188,7 +218,8 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox {
_drag = HorizontalDragGestureRecognizer() _drag = HorizontalDragGestureRecognizer()
..onStart = _handleDragStart ..onStart = _handleDragStart
..onUpdate = _handleDragUpdate ..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd; ..onEnd = _handleDragEnd
..dragStartBehavior = dragStartBehavior;
_positionController = AnimationController( _positionController = AnimationController(
duration: _kToggleDuration, duration: _kToggleDuration,
value: value ? 1.0 : 0.0, value: value ? 1.0 : 0.0,
...@@ -276,6 +307,14 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox { ...@@ -276,6 +307,14 @@ class _RenderCupertinoSwitch extends RenderConstrainedBox {
markNeedsPaint(); markNeedsPaint();
} }
DragStartBehavior get dragStartBehavior => _drag.dragStartBehavior;
set dragStartBehavior(DragStartBehavior value) {
assert(value != null);
if (_drag.dragStartBehavior == value)
return;
_drag.dragStartBehavior = value;
}
bool get isInteractive => onChanged != null; bool get isInteractive => onChanged != null;
TapGestureRecognizer _tap; TapGestureRecognizer _tap;
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'arena.dart'; import 'arena.dart';
import 'constants.dart'; import 'constants.dart';
import 'drag_details.dart'; import 'drag_details.dart';
...@@ -48,7 +50,36 @@ typedef GestureDragCancelCallback = void Function(); ...@@ -48,7 +50,36 @@ typedef GestureDragCancelCallback = void Function();
/// * [PanGestureRecognizer], for drags that are not locked to a single axis. /// * [PanGestureRecognizer], for drags that are not locked to a single axis.
abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
/// Initialize the object. /// Initialize the object.
DragGestureRecognizer({ Object debugOwner }) : super(debugOwner: debugOwner); ///
/// [dragStartBehavior] must not be null.
DragGestureRecognizer({
Object debugOwner,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(dragStartBehavior != null),
super(debugOwner: debugOwner);
/// Configure the behavior of offsets sent to [onStart].
///
/// If set to [DragStartBehavior.start], the [onStart] callback will be called at the time and
/// position when the gesture detector wins the arena. If [DragStartBehavior.down],
/// [onStart] will be called at the time and position when a down event was
/// first detected.
///
/// For more information about the gesture arena:
/// https://flutter.io/docs/development/ui/advanced/gestures#gesture-disambiguation
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// ## Example:
///
/// A finger presses down on the screen with offset (500.0, 500.0),
/// and then moves to position (510.0, 500.0) before winning the arena.
/// With [dragStartBehavior] set to [DragStartBehavior.down], the [onStart]
/// callback will be called at the time corresponding to the touch's position
/// at (500.0, 500.0). If it is instead set to [DragStartBehavior.start],
/// [onStart] will be called at the time corresponding to the touch's position
/// at (510.0, 500.0).
DragStartBehavior dragStartBehavior;
/// A pointer has contacted the screen and might begin to move. /// A pointer has contacted the screen and might begin to move.
/// ///
...@@ -60,6 +91,11 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -60,6 +91,11 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
/// ///
/// The position of the pointer is provided in the callback's `details` /// The position of the pointer is provided in the callback's `details`
/// argument, which is a [DragStartDetails] object. /// argument, which is a [DragStartDetails] object.
///
/// Depending on the value of [dragStartBehavior], this function will be
/// called on the initial touch down, if set to [DragStartBehavior.down] or
/// when the drag gesture is first detected, if set to
/// [DragStartBehavior.start].
GestureDragStartCallback onStart; GestureDragStartCallback onStart;
/// A pointer that is in contact with the screen and moving has moved again. /// A pointer that is in contact with the screen and moving has moved again.
...@@ -163,6 +199,16 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -163,6 +199,16 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
_state = _DragState.accepted; _state = _DragState.accepted;
final Offset delta = _pendingDragOffset; final Offset delta = _pendingDragOffset;
final Duration timestamp = _lastPendingEventTimestamp; final Duration timestamp = _lastPendingEventTimestamp;
Offset updateDelta;
switch (dragStartBehavior) {
case DragStartBehavior.start:
_initialPosition = _initialPosition + delta;
updateDelta = Offset.zero;
break;
case DragStartBehavior.down:
updateDelta = _getDeltaForDetails(delta);
break;
}
_pendingDragOffset = Offset.zero; _pendingDragOffset = Offset.zero;
_lastPendingEventTimestamp = null; _lastPendingEventTimestamp = null;
if (onStart != null) { if (onStart != null) {
...@@ -171,13 +217,12 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -171,13 +217,12 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
globalPosition: _initialPosition, globalPosition: _initialPosition,
))); )));
} }
if (delta != Offset.zero && onUpdate != null) { if (updateDelta != Offset.zero && onUpdate != null) {
final Offset deltaForDetails = _getDeltaForDetails(delta);
invokeCallback<void>('onUpdate', () => onUpdate(DragUpdateDetails( invokeCallback<void>('onUpdate', () => onUpdate(DragUpdateDetails(
sourceTimeStamp: timestamp, sourceTimeStamp: timestamp,
delta: deltaForDetails, delta: updateDelta,
primaryDelta: _getPrimaryValueFromOffset(delta), primaryDelta: _getPrimaryValueFromOffset(updateDelta),
globalPosition: _initialPosition + deltaForDetails, globalPosition: _initialPosition + updateDelta, // Only adds delta for down behaviour
))); )));
} }
} }
...@@ -232,6 +277,11 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -232,6 +277,11 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
_velocityTrackers.clear(); _velocityTrackers.clear();
super.dispose(); super.dispose();
} }
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(EnumProperty<DragStartBehavior>('Start Behavior', dragStartBehavior));
}
} }
/// Recognizes movement in the vertical direction. /// Recognizes movement in the vertical direction.
...@@ -280,7 +330,8 @@ class VerticalDragGestureRecognizer extends DragGestureRecognizer { ...@@ -280,7 +330,8 @@ class VerticalDragGestureRecognizer extends DragGestureRecognizer {
/// track each touch point independently. /// track each touch point independently.
class HorizontalDragGestureRecognizer extends DragGestureRecognizer { class HorizontalDragGestureRecognizer extends DragGestureRecognizer {
/// Create a gesture recognizer for interactions in the horizontal axis. /// Create a gesture recognizer for interactions in the horizontal axis.
HorizontalDragGestureRecognizer({ Object debugOwner }) : super(debugOwner: debugOwner); HorizontalDragGestureRecognizer({ Object debugOwner }) :
super(debugOwner: debugOwner);
@override @override
bool _isFlingGesture(VelocityEstimate estimate) { bool _isFlingGesture(VelocityEstimate estimate) {
......
...@@ -24,6 +24,24 @@ export 'pointer_router.dart' show PointerRouter; ...@@ -24,6 +24,24 @@ export 'pointer_router.dart' show PointerRouter;
/// anonymous functions that return objects of particular types. /// anonymous functions that return objects of particular types.
typedef RecognizerCallback<T> = T Function(); typedef RecognizerCallback<T> = T Function();
/// Configuration of offset passed to [DragStartDetails].
///
/// The settings determines when a drag formally starts when the user
/// initiates a drag.
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
enum DragStartBehavior {
/// Set the initial offset, at the position where the first down even was
/// detected.
down,
/// Set the initial position at the position where the drag start event was
/// detected.
start,
}
/// The base class that all gesture recognizers inherit from. /// The base class that all gesture recognizers inherit from.
/// ///
/// Provides a basic API that can be used by classes that work with /// Provides a basic API that can be used by classes that work with
......
...@@ -8,6 +8,7 @@ import 'dart:math' as math; ...@@ -8,6 +8,7 @@ import 'dart:math' as math;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'button_bar.dart'; import 'button_bar.dart';
import 'button_theme.dart'; import 'button_theme.dart';
...@@ -250,10 +251,12 @@ class DayPicker extends StatelessWidget { ...@@ -250,10 +251,12 @@ class DayPicker extends StatelessWidget {
@required this.lastDate, @required this.lastDate,
@required this.displayedMonth, @required this.displayedMonth,
this.selectableDayPredicate, this.selectableDayPredicate,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(currentDate != null), assert(currentDate != null),
assert(onChanged != null), assert(onChanged != null),
assert(displayedMonth != null), assert(displayedMonth != null),
assert(dragStartBehavior != null),
assert(!firstDate.isAfter(lastDate)), assert(!firstDate.isAfter(lastDate)),
assert(selectedDate.isAfter(firstDate) || selectedDate.isAtSameMomentAs(firstDate)), assert(selectedDate.isAfter(firstDate) || selectedDate.isAtSameMomentAs(firstDate)),
super(key: key); super(key: key);
...@@ -281,6 +284,13 @@ class DayPicker extends StatelessWidget { ...@@ -281,6 +284,13 @@ 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;
/// The initial drag behavior of the date picker wheel.
///
/// If set to [DragStartBehavior.start], picker drag behavior will begin upon the
/// drag gesture winning the arena. If set to [DragStartBehavior.down] it will
/// begin when a down event is first detected.
final DragStartBehavior dragStartBehavior;
/// Builds widgets showing abbreviated days of week. The first widget in the /// Builds widgets showing abbreviated days of week. The first widget in the
/// returned list corresponds to the first day of week for the current locale. /// returned list corresponds to the first day of week for the current locale.
/// ///
...@@ -442,6 +452,7 @@ class DayPicker extends StatelessWidget { ...@@ -442,6 +452,7 @@ class DayPicker extends StatelessWidget {
onChanged(dayToBuild); onChanged(dayToBuild);
}, },
child: dayWidget, child: dayWidget,
dragStartBehavior: dragStartBehavior,
); );
} }
...@@ -502,6 +513,7 @@ class MonthPicker extends StatefulWidget { ...@@ -502,6 +513,7 @@ class MonthPicker extends StatefulWidget {
@required this.firstDate, @required this.firstDate,
@required this.lastDate, @required this.lastDate,
this.selectableDayPredicate, this.selectableDayPredicate,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(onChanged != null), assert(onChanged != null),
assert(!firstDate.isAfter(lastDate)), assert(!firstDate.isAfter(lastDate)),
...@@ -525,6 +537,9 @@ class MonthPicker extends StatefulWidget { ...@@ -525,6 +537,9 @@ class MonthPicker extends StatefulWidget {
/// Optional user supplied predicate function to customize selectable days. /// Optional user supplied predicate function to customize selectable days.
final SelectableDayPredicate selectableDayPredicate; final SelectableDayPredicate selectableDayPredicate;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
_MonthPickerState createState() => _MonthPickerState(); _MonthPickerState createState() => _MonthPickerState();
} }
...@@ -609,6 +624,7 @@ class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStat ...@@ -609,6 +624,7 @@ class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStat
lastDate: widget.lastDate, lastDate: widget.lastDate,
displayedMonth: month, displayedMonth: month,
selectableDayPredicate: widget.selectableDayPredicate, selectableDayPredicate: widget.selectableDayPredicate,
dragStartBehavior: widget.dragStartBehavior,
); );
} }
...@@ -669,6 +685,7 @@ class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStat ...@@ -669,6 +685,7 @@ class _MonthPickerState extends State<MonthPicker> with SingleTickerProviderStat
return false; return false;
}, },
child: PageView.builder( child: PageView.builder(
dragStartBehavior: widget.dragStartBehavior,
key: ValueKey<DateTime>(widget.selectedDate), key: ValueKey<DateTime>(widget.selectedDate),
controller: _dayPickerController, controller: _dayPickerController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
...@@ -759,6 +776,7 @@ class YearPicker extends StatefulWidget { ...@@ -759,6 +776,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.start,
}) : assert(selectedDate != null), }) : assert(selectedDate != null),
assert(onChanged != null), assert(onChanged != null),
assert(!firstDate.isAfter(lastDate)), assert(!firstDate.isAfter(lastDate)),
...@@ -778,6 +796,9 @@ class YearPicker extends StatefulWidget { ...@@ -778,6 +796,9 @@ class YearPicker extends StatefulWidget {
/// The latest date the user is permitted to pick. /// The latest date the user is permitted to pick.
final DateTime lastDate; final DateTime lastDate;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
_YearPickerState createState() => _YearPickerState(); _YearPickerState createState() => _YearPickerState();
} }
...@@ -801,6 +822,7 @@ class _YearPickerState extends State<YearPicker> { ...@@ -801,6 +822,7 @@ class _YearPickerState extends State<YearPicker> {
final ThemeData themeData = Theme.of(context); final ThemeData themeData = Theme.of(context);
final TextStyle style = themeData.textTheme.body1; final TextStyle style = themeData.textTheme.body1;
return ListView.builder( return ListView.builder(
dragStartBehavior: widget.dragStartBehavior,
controller: scrollController, controller: scrollController,
itemExtent: _itemExtent, itemExtent: _itemExtent,
itemCount: widget.lastDate.year - widget.firstDate.year + 1, itemCount: widget.lastDate.year - widget.firstDate.year + 1,
......
...@@ -6,6 +6,7 @@ import 'dart:math'; ...@@ -6,6 +6,7 @@ import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'colors.dart'; import 'colors.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -179,7 +180,9 @@ class DrawerController extends StatefulWidget { ...@@ -179,7 +180,9 @@ class DrawerController extends StatefulWidget {
@required this.child, @required this.child,
@required this.alignment, @required this.alignment,
this.drawerCallback, this.drawerCallback,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(child != null), }) : assert(child != null),
assert(dragStartBehavior != null),
assert(alignment != null), assert(alignment != null),
super(key: key); super(key: key);
...@@ -197,6 +200,26 @@ class DrawerController extends StatefulWidget { ...@@ -197,6 +200,26 @@ 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;
/// {@template flutter.material.drawer.dragStartBehavior}
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], the drag behavior used for opening
/// and closing a drawer will begin upon the detection of a drag gesture. If
/// set to [DragStartBehavior.down] it will begin when a down event is first
/// detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
/// {@endtemplate}
final DragStartBehavior dragStartBehavior;
@override @override
DrawerControllerState createState() => DrawerControllerState(); DrawerControllerState createState() => DrawerControllerState();
} }
...@@ -399,6 +422,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -399,6 +422,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
onHorizontalDragEnd: _settle, onHorizontalDragEnd: _settle,
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
excludeFromSemantics: true, excludeFromSemantics: true,
dragStartBehavior: widget.dragStartBehavior,
child: Container(width: dragAreaWidth), child: Container(width: dragAreaWidth),
), ),
); );
...@@ -410,6 +434,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -410,6 +434,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
onHorizontalDragEnd: _settle, onHorizontalDragEnd: _settle,
onHorizontalDragCancel: _handleDragCancel, onHorizontalDragCancel: _handleDragCancel,
excludeFromSemantics: true, excludeFromSemantics: true,
dragStartBehavior: widget.dragStartBehavior,
child: RepaintBoundary( child: RepaintBoundary(
child: Stack( child: Stack(
children: <Widget>[ children: <Widget>[
......
...@@ -6,6 +6,7 @@ import 'dart:math' as math; ...@@ -6,6 +6,7 @@ import 'dart:math' as math;
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'button_bar.dart'; import 'button_bar.dart';
import 'button_theme.dart'; import 'button_theme.dart';
...@@ -74,9 +75,11 @@ class PaginatedDataTable extends StatefulWidget { ...@@ -74,9 +75,11 @@ 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.start,
@required this.source @required this.source
}) : assert(header != null), }) : assert(header != null),
assert(columns != null), assert(columns != null),
assert(dragStartBehavior != null),
assert(columns.isNotEmpty), assert(columns.isNotEmpty),
assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)), assert(sortColumnIndex == null || (sortColumnIndex >= 0 && sortColumnIndex < columns.length)),
assert(sortAscending != null), assert(sortAscending != null),
...@@ -170,6 +173,9 @@ class PaginatedDataTable extends StatefulWidget { ...@@ -170,6 +173,9 @@ class PaginatedDataTable extends StatefulWidget {
/// [PaginatedDataTable] constructor is called. /// [PaginatedDataTable] constructor is called.
final DataTableSource source; final DataTableSource source;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
PaginatedDataTableState createState() => PaginatedDataTableState(); PaginatedDataTableState createState() => PaginatedDataTableState();
} }
...@@ -417,6 +423,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> { ...@@ -417,6 +423,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
), ),
SingleChildScrollView( SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
dragStartBehavior: widget.dragStartBehavior,
child: DataTable( child: DataTable(
key: _tableKey, key: _tableKey,
columns: widget.columns, columns: widget.columns,
...@@ -435,6 +442,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> { ...@@ -435,6 +442,7 @@ class PaginatedDataTableState extends State<PaginatedDataTable> {
child: Container( child: Container(
height: 56.0, height: 56.0,
child: SingleChildScrollView( child: SingleChildScrollView(
dragStartBehavior: widget.dragStartBehavior,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
reverse: true, reverse: true,
child: Row( child: Row(
......
...@@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'app_bar.dart'; import 'app_bar.dart';
import 'bottom_sheet.dart'; import 'bottom_sheet.dart';
...@@ -732,7 +733,10 @@ class Scaffold extends StatefulWidget { ...@@ -732,7 +733,10 @@ class Scaffold extends StatefulWidget {
this.backgroundColor, this.backgroundColor,
this.resizeToAvoidBottomPadding = true, this.resizeToAvoidBottomPadding = true,
this.primary = true, this.primary = true,
}) : assert(primary != null), super(key: key); this.drawerDragStartBehavior = DragStartBehavior.start,
}) : assert(primary != null),
assert(drawerDragStartBehavior != null),
super(key: key);
/// An app bar to display at the top of the scaffold. /// An app bar to display at the top of the scaffold.
final PreferredSizeWidget appBar; final PreferredSizeWidget appBar;
...@@ -865,6 +869,9 @@ class Scaffold extends StatefulWidget { ...@@ -865,6 +869,9 @@ class Scaffold extends StatefulWidget {
/// [AppBar.primary], is true. /// [AppBar.primary], is true.
final bool primary; final bool primary;
/// {@macro flutter.material.drawer.dragStartBehavior}
final DragStartBehavior drawerDragStartBehavior;
/// The state from the closest instance of this class that encloses the given context. /// The state from the closest instance of this class that encloses the given context.
/// ///
/// Typical usage is as follows: /// Typical usage is as follows:
...@@ -1500,6 +1507,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin { ...@@ -1500,6 +1507,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
alignment: DrawerAlignment.end, alignment: DrawerAlignment.end,
child: widget.endDrawer, child: widget.endDrawer,
drawerCallback: _endDrawerOpenedCallback, drawerCallback: _endDrawerOpenedCallback,
dragStartBehavior: widget.drawerDragStartBehavior,
), ),
_ScaffoldSlot.endDrawer, _ScaffoldSlot.endDrawer,
// remove the side padding from the side we're not touching // remove the side padding from the side we're not touching
...@@ -1521,6 +1529,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin { ...@@ -1521,6 +1529,7 @@ class ScaffoldState extends State<Scaffold> with TickerProviderStateMixin {
alignment: DrawerAlignment.start, alignment: DrawerAlignment.start,
child: widget.drawer, child: widget.drawer,
drawerCallback: _drawerOpenedCallback, drawerCallback: _drawerOpenedCallback,
dragStartBehavior: widget.drawerDragStartBehavior,
), ),
_ScaffoldSlot.drawer, _ScaffoldSlot.drawer,
// remove the side padding from the side we're not touching // remove the side padding from the side we're not touching
......
...@@ -73,7 +73,9 @@ class Switch extends StatefulWidget { ...@@ -73,7 +73,9 @@ class Switch extends StatefulWidget {
this.activeThumbImage, this.activeThumbImage,
this.inactiveThumbImage, this.inactiveThumbImage,
this.materialTapTargetSize, this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.start,
}) : _switchType = _SwitchType.material, }) : _switchType = _SwitchType.material,
assert(dragStartBehavior != null),
super(key: key); super(key: key);
/// Creates a [CupertinoSwitch] if the target platform is iOS, creates a /// Creates a [CupertinoSwitch] if the target platform is iOS, creates a
...@@ -95,6 +97,7 @@ class Switch extends StatefulWidget { ...@@ -95,6 +97,7 @@ class Switch extends StatefulWidget {
this.activeThumbImage, this.activeThumbImage,
this.inactiveThumbImage, this.inactiveThumbImage,
this.materialTapTargetSize, this.materialTapTargetSize,
this.dragStartBehavior = DragStartBehavior.start,
}) : _switchType = _SwitchType.adaptive, }) : _switchType = _SwitchType.adaptive,
super(key: key); super(key: key);
...@@ -174,6 +177,9 @@ class Switch extends StatefulWidget { ...@@ -174,6 +177,9 @@ class Switch extends StatefulWidget {
final _SwitchType _switchType; final _SwitchType _switchType;
/// {@macro flutter.cupertino.switch.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
_SwitchState createState() => _SwitchState(); _SwitchState createState() => _SwitchState();
...@@ -219,6 +225,7 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin { ...@@ -219,6 +225,7 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
} }
return _SwitchRenderObjectWidget( return _SwitchRenderObjectWidget(
dragStartBehavior: widget.dragStartBehavior,
value: widget.value, value: widget.value,
activeColor: activeThumbColor, activeColor: activeThumbColor,
inactiveColor: inactiveThumbColor, inactiveColor: inactiveThumbColor,
...@@ -240,6 +247,7 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin { ...@@ -240,6 +247,7 @@ class _SwitchState extends State<Switch> with TickerProviderStateMixin {
height: size.height, height: size.height,
alignment: Alignment.center, alignment: Alignment.center,
child: CupertinoSwitch( child: CupertinoSwitch(
dragStartBehavior: widget.dragStartBehavior,
value: widget.value, value: widget.value,
onChanged: widget.onChanged, onChanged: widget.onChanged,
activeColor: widget.activeColor, activeColor: widget.activeColor,
...@@ -284,6 +292,7 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -284,6 +292,7 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
this.onChanged, this.onChanged,
this.vsync, this.vsync,
this.additionalConstraints, this.additionalConstraints,
this.dragStartBehavior,
}) : super(key: key); }) : super(key: key);
final bool value; final bool value;
...@@ -297,10 +306,12 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -297,10 +306,12 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
final ValueChanged<bool> onChanged; final ValueChanged<bool> onChanged;
final TickerProvider vsync; final TickerProvider vsync;
final BoxConstraints additionalConstraints; final BoxConstraints additionalConstraints;
final DragStartBehavior dragStartBehavior;
@override @override
_RenderSwitch createRenderObject(BuildContext context) { _RenderSwitch createRenderObject(BuildContext context) {
return _RenderSwitch( return _RenderSwitch(
dragStartBehavior: dragStartBehavior,
value: value, value: value,
activeColor: activeColor, activeColor: activeColor,
inactiveColor: inactiveColor, inactiveColor: inactiveColor,
...@@ -330,6 +341,7 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget { ...@@ -330,6 +341,7 @@ class _SwitchRenderObjectWidget extends LeafRenderObjectWidget {
..onChanged = onChanged ..onChanged = onChanged
..textDirection = Directionality.of(context) ..textDirection = Directionality.of(context)
..additionalConstraints = additionalConstraints ..additionalConstraints = additionalConstraints
..dragStartBehavior = dragStartBehavior
..vsync = vsync; ..vsync = vsync;
} }
} }
...@@ -348,6 +360,7 @@ class _RenderSwitch extends RenderToggleable { ...@@ -348,6 +360,7 @@ class _RenderSwitch extends RenderToggleable {
@required TextDirection textDirection, @required TextDirection textDirection,
ValueChanged<bool> onChanged, ValueChanged<bool> onChanged,
@required TickerProvider vsync, @required TickerProvider vsync,
DragStartBehavior dragStartBehavior,
}) : assert(textDirection != null), }) : assert(textDirection != null),
_activeThumbImage = activeThumbImage, _activeThumbImage = activeThumbImage,
_inactiveThumbImage = inactiveThumbImage, _inactiveThumbImage = inactiveThumbImage,
...@@ -367,7 +380,8 @@ class _RenderSwitch extends RenderToggleable { ...@@ -367,7 +380,8 @@ class _RenderSwitch extends RenderToggleable {
_drag = HorizontalDragGestureRecognizer() _drag = HorizontalDragGestureRecognizer()
..onStart = _handleDragStart ..onStart = _handleDragStart
..onUpdate = _handleDragUpdate ..onUpdate = _handleDragUpdate
..onEnd = _handleDragEnd; ..onEnd = _handleDragEnd
..dragStartBehavior = dragStartBehavior;
} }
ImageProvider get activeThumbImage => _activeThumbImage; ImageProvider get activeThumbImage => _activeThumbImage;
...@@ -428,6 +442,14 @@ class _RenderSwitch extends RenderToggleable { ...@@ -428,6 +442,14 @@ class _RenderSwitch extends RenderToggleable {
markNeedsPaint(); markNeedsPaint();
} }
DragStartBehavior get dragStartBehavior => _drag.dragStartBehavior;
set dragStartBehavior(DragStartBehavior value) {
assert(value != null);
if(_drag.dragStartBehavior == value)
return;
_drag.dragStartBehavior = value;
}
@override @override
void detach() { void detach() {
_cachedThumbPainter?.dispose(); _cachedThumbPainter?.dispose();
......
...@@ -7,6 +7,7 @@ import 'dart:ui' show lerpDouble; ...@@ -7,6 +7,7 @@ import 'dart:ui' show lerpDouble;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'app_bar.dart'; import 'app_bar.dart';
import 'colors.dart'; import 'colors.dart';
...@@ -549,9 +550,11 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -549,9 +550,11 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
this.labelPadding, this.labelPadding,
this.unselectedLabelColor, this.unselectedLabelColor,
this.unselectedLabelStyle, this.unselectedLabelStyle,
this.dragStartBehavior = DragStartBehavior.start,
this.onTap, this.onTap,
}) : assert(tabs != null), }) : assert(tabs != null),
assert(isScrollable != null), assert(isScrollable != null),
assert(dragStartBehavior != null),
assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)), assert(indicator != null || (indicatorWeight != null && indicatorWeight > 0.0)),
assert(indicator != null || (indicatorPadding != null)), assert(indicator != null || (indicatorPadding != null)),
super(key: key); super(key: key);
...@@ -662,6 +665,9 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget { ...@@ -662,6 +665,9 @@ class TabBar extends StatefulWidget implements PreferredSizeWidget {
/// is null then the text style of the theme's body2 definition is used. /// is null then the text style of the theme's body2 definition is used.
final TextStyle unselectedLabelStyle; final TextStyle unselectedLabelStyle;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// An optional callback that's called when the [TabBar] is tapped. /// An optional callback that's called when the [TabBar] is tapped.
/// ///
/// The callback is applied to the index of the tab where the tap occurred. /// The callback is applied to the index of the tab where the tap occurred.
...@@ -1011,6 +1017,7 @@ class _TabBarState extends State<TabBar> { ...@@ -1011,6 +1017,7 @@ class _TabBarState extends State<TabBar> {
if (widget.isScrollable) { if (widget.isScrollable) {
_scrollController ??= _TabBarScrollController(this); _scrollController ??= _TabBarScrollController(this);
tabBar = SingleChildScrollView( tabBar = SingleChildScrollView(
dragStartBehavior: widget.dragStartBehavior,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
controller: _scrollController, controller: _scrollController,
child: tabBar, child: tabBar,
...@@ -1035,7 +1042,10 @@ class TabBarView extends StatefulWidget { ...@@ -1035,7 +1042,10 @@ class TabBarView extends StatefulWidget {
@required this.children, @required this.children,
this.controller, this.controller,
this.physics, this.physics,
}) : assert(children != null), super(key: key); this.dragStartBehavior = DragStartBehavior.start,
}) : assert(children != null),
assert(dragStartBehavior != null),
super(key: key);
/// This widget's selection and animation state. /// This widget's selection and animation state.
/// ///
...@@ -1057,6 +1067,9 @@ class TabBarView extends StatefulWidget { ...@@ -1057,6 +1067,9 @@ class TabBarView extends StatefulWidget {
/// Defaults to matching platform conventions. /// Defaults to matching platform conventions.
final ScrollPhysics physics; final ScrollPhysics physics;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
_TabBarViewState createState() => _TabBarViewState(); _TabBarViewState createState() => _TabBarViewState();
} }
...@@ -1201,6 +1214,7 @@ class _TabBarViewState extends State<TabBarView> { ...@@ -1201,6 +1214,7 @@ class _TabBarViewState extends State<TabBarView> {
return NotificationListener<ScrollNotification>( return NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification, onNotification: _handleScrollNotification,
child: PageView( child: PageView(
dragStartBehavior: widget.dragStartBehavior,
controller: _pageController, controller: _pageController,
physics: widget.physics == null ? _kTabBarViewPhysics : _kTabBarViewPhysics.applyTo(widget.physics), physics: widget.physics == null ? _kTabBarViewPhysics : _kTabBarViewPhysics.applyTo(widget.physics),
children: _children, children: _children,
......
...@@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart';
import 'debug.dart'; import 'debug.dart';
import 'feedback.dart'; import 'feedback.dart';
...@@ -127,6 +128,7 @@ class TextField extends StatefulWidget { ...@@ -127,6 +128,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.start,
this.enableInteractiveSelection, this.enableInteractiveSelection,
this.onTap, this.onTap,
}) : assert(textAlign != null), }) : assert(textAlign != null),
...@@ -135,6 +137,7 @@ class TextField extends StatefulWidget { ...@@ -135,6 +137,7 @@ class TextField extends StatefulWidget {
assert(autocorrect != null), assert(autocorrect != null),
assert(maxLengthEnforced != null), assert(maxLengthEnforced != null),
assert(scrollPadding != null), assert(scrollPadding != null),
assert(dragStartBehavior != null),
assert(maxLines == null || maxLines > 0), assert(maxLines == null || maxLines > 0),
assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0), assert(maxLength == null || maxLength == TextField.noMaxLength || maxLength > 0),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
...@@ -346,6 +349,9 @@ class TextField extends StatefulWidget { ...@@ -346,6 +349,9 @@ class TextField extends StatefulWidget {
/// {@macro flutter.widgets.editableText.enableInteractiveSelection} /// {@macro flutter.widgets.editableText.enableInteractiveSelection}
final bool enableInteractiveSelection; final bool enableInteractiveSelection;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.rendering.editable.selectionEnabled} /// {@macro flutter.rendering.editable.selectionEnabled}
bool get selectionEnabled { bool get selectionEnabled {
return enableInteractiveSelection ?? !obscureText; return enableInteractiveSelection ?? !obscureText;
...@@ -669,6 +675,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi ...@@ -669,6 +675,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
scrollPadding: widget.scrollPadding, scrollPadding: widget.scrollPadding,
keyboardAppearance: keyboardAppearance, keyboardAppearance: keyboardAppearance,
enableInteractiveSelection: widget.enableInteractiveSelection, enableInteractiveSelection: widget.enableInteractiveSelection,
dragStartBehavior: widget.dragStartBehavior,
), ),
); );
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/gestures.dart';
import 'automatic_keep_alive.dart'; import 'automatic_keep_alive.dart';
import 'basic.dart'; import 'basic.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -82,8 +84,10 @@ class Dismissible extends StatefulWidget { ...@@ -82,8 +84,10 @@ 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.start,
}) : assert(key != null), }) : assert(key != null),
assert(secondaryBackground != null ? background != null : true), assert(secondaryBackground != null ? background != null : true),
assert(dragStartBehavior != null),
super(key: key); super(key: key);
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
...@@ -142,6 +146,23 @@ class Dismissible extends StatefulWidget { ...@@ -142,6 +146,23 @@ class Dismissible extends StatefulWidget {
/// it is positive or negative. /// it is positive or negative.
final double crossAxisEndOffset; final double crossAxisEndOffset;
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], the drag gesture used to dismiss a
/// dismissible will begin upon the detection of a drag gesture. If set to
/// [DragStartBehavior.down] it will begin when a down event is first detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
final DragStartBehavior dragStartBehavior;
@override @override
_DismissibleState createState() => _DismissibleState(); _DismissibleState createState() => _DismissibleState();
} }
...@@ -327,8 +348,8 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin ...@@ -327,8 +348,8 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
Tween<Offset>( Tween<Offset>(
begin: Offset.zero, begin: Offset.zero,
end: _directionIsXAxis end: _directionIsXAxis
? Offset(end, widget.crossAxisEndOffset) ? Offset(end, widget.crossAxisEndOffset)
: Offset(widget.crossAxisEndOffset, end), : Offset(widget.crossAxisEndOffset, end),
), ),
); );
} }
...@@ -514,7 +535,6 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin ...@@ -514,7 +535,6 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
children.add(content); children.add(content);
content = Stack(children: children); content = Stack(children: children);
} }
// We are not resizing but we may be being dragging in widget.direction. // We are not resizing but we may be being dragging in widget.direction.
return GestureDetector( return GestureDetector(
onHorizontalDragStart: _directionIsXAxis ? _handleDragStart : null, onHorizontalDragStart: _directionIsXAxis ? _handleDragStart : null,
...@@ -524,7 +544,8 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin ...@@ -524,7 +544,8 @@ class _DismissibleState extends State<Dismissible> with TickerProviderStateMixin
onVerticalDragUpdate: _directionIsXAxis ? null : _handleDragUpdate, onVerticalDragUpdate: _directionIsXAxis ? null : _handleDragUpdate,
onVerticalDragEnd: _directionIsXAxis ? null : _handleDragEnd, onVerticalDragEnd: _directionIsXAxis ? null : _handleDragEnd,
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: content child: content,
dragStartBehavior: widget.dragStartBehavior,
); );
} }
} }
......
...@@ -8,6 +8,7 @@ import 'dart:ui' as ui; ...@@ -8,6 +8,7 @@ import 'dart:ui' as ui;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'automatic_keep_alive.dart'; import 'automatic_keep_alive.dart';
import 'basic.dart'; import 'basic.dart';
...@@ -184,7 +185,8 @@ class EditableText extends StatefulWidget { ...@@ -184,7 +185,8 @@ class EditableText extends StatefulWidget {
/// default to [TextInputType.multiline]. /// default to [TextInputType.multiline].
/// ///
/// The [controller], [focusNode], [style], [cursorColor], [backgroundCursorColor], /// The [controller], [focusNode], [style], [cursorColor], [backgroundCursorColor],
/// [textAlign], and [rendererIgnoresPointer] arguments must not be null. /// [textAlign], [dragStartBehavior] and [rendererIgnoresPointer] arguments
/// must not be null.
EditableText({ EditableText({
Key key, Key key,
@required this.controller, @required this.controller,
...@@ -215,6 +217,7 @@ class EditableText extends StatefulWidget { ...@@ -215,6 +217,7 @@ class EditableText extends StatefulWidget {
this.cursorRadius, this.cursorRadius,
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.start,
this.enableInteractiveSelection, this.enableInteractiveSelection,
}) : assert(controller != null), }) : assert(controller != null),
assert(focusNode != null), assert(focusNode != null),
...@@ -228,6 +231,7 @@ class EditableText extends StatefulWidget { ...@@ -228,6 +231,7 @@ class EditableText extends StatefulWidget {
assert(autofocus != null), assert(autofocus != null),
assert(rendererIgnoresPointer != null), assert(rendererIgnoresPointer != null),
assert(scrollPadding != null), assert(scrollPadding != null),
assert(dragStartBehavior != null),
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline), keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
inputFormatters = maxLines == 1 inputFormatters = maxLines == 1
? ( ? (
...@@ -284,6 +288,10 @@ class EditableText extends StatefulWidget { ...@@ -284,6 +288,10 @@ class EditableText extends StatefulWidget {
/// its left. /// its left.
/// ///
/// Defaults to the ambient [Directionality], if any. /// Defaults to the ambient [Directionality], if any.
///
/// See also:
///
/// * {@macro flutter.gestures.monodrag.dragStartExample}
/// {@endtemplate} /// {@endtemplate}
final TextDirection textDirection; final TextDirection textDirection;
...@@ -494,6 +502,9 @@ class EditableText extends StatefulWidget { ...@@ -494,6 +502,9 @@ class EditableText extends StatefulWidget {
/// Defaults to false, resulting in a typical blinking cursor. /// Defaults to false, resulting in a typical blinking cursor.
static bool debugDeterministicCursor = false; static bool debugDeterministicCursor = false;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.rendering.editable.selectionEnabled} /// {@macro flutter.rendering.editable.selectionEnabled}
bool get selectionEnabled { bool get selectionEnabled {
return enableInteractiveSelection ?? !obscureText; return enableInteractiveSelection ?? !obscureText;
...@@ -840,6 +851,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -840,6 +851,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
renderObject: renderObject, renderObject: renderObject,
selectionControls: widget.selectionControls, selectionControls: widget.selectionControls,
selectionDelegate: this, selectionDelegate: this,
dragStartBehavior: widget.dragStartBehavior,
); );
final bool longPress = cause == SelectionChangedCause.longPress; final bool longPress = cause == SelectionChangedCause.longPress;
if (cause != SelectionChangedCause.keyboard && (_value.text.isNotEmpty || longPress)) if (cause != SelectionChangedCause.keyboard && (_value.text.isNotEmpty || longPress))
...@@ -1061,6 +1073,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -1061,6 +1073,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
axisDirection: _isMultiline ? AxisDirection.down : AxisDirection.right, axisDirection: _isMultiline ? AxisDirection.down : AxisDirection.right,
controller: _scrollController, controller: _scrollController,
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
dragStartBehavior: widget.dragStartBehavior,
viewportBuilder: (BuildContext context, ViewportOffset offset) { viewportBuilder: (BuildContext context, ViewportOffset offset) {
return CompositedTransformTarget( return CompositedTransformTarget(
link: _layerLink, link: _layerLink,
......
...@@ -184,8 +184,10 @@ class GestureDetector extends StatelessWidget { ...@@ -184,8 +184,10 @@ class GestureDetector extends StatelessWidget {
this.onScaleUpdate, this.onScaleUpdate,
this.onScaleEnd, this.onScaleEnd,
this.behavior, this.behavior,
this.excludeFromSemantics = false this.excludeFromSemantics = false,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(excludeFromSemantics != null), }) : assert(excludeFromSemantics != null),
assert(dragStartBehavior != null),
assert(() { assert(() {
final bool haveVerticalDrag = onVerticalDragStart != null || onVerticalDragUpdate != null || onVerticalDragEnd != null; final bool haveVerticalDrag = onVerticalDragStart != null || onVerticalDragUpdate != null || onVerticalDragEnd != null;
final bool haveHorizontalDrag = onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null; final bool haveHorizontalDrag = onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null;
...@@ -370,6 +372,23 @@ class GestureDetector extends StatelessWidget { ...@@ -370,6 +372,23 @@ class GestureDetector extends StatelessWidget {
/// duplication of information. /// duplication of information.
final bool excludeFromSemantics; final bool excludeFromSemantics;
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], gesture drag behavior will
/// begin upon the detection of a drag gesture. If set to
/// [DragStartBehavior.down] it will begin when a down event is first detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
final DragStartBehavior dragStartBehavior;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{}; final Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
...@@ -421,7 +440,8 @@ class GestureDetector extends StatelessWidget { ...@@ -421,7 +440,8 @@ class GestureDetector extends StatelessWidget {
..onStart = onVerticalDragStart ..onStart = onVerticalDragStart
..onUpdate = onVerticalDragUpdate ..onUpdate = onVerticalDragUpdate
..onEnd = onVerticalDragEnd ..onEnd = onVerticalDragEnd
..onCancel = onVerticalDragCancel; ..onCancel = onVerticalDragCancel
..dragStartBehavior = dragStartBehavior;
}, },
); );
} }
...@@ -439,7 +459,8 @@ class GestureDetector extends StatelessWidget { ...@@ -439,7 +459,8 @@ class GestureDetector extends StatelessWidget {
..onStart = onHorizontalDragStart ..onStart = onHorizontalDragStart
..onUpdate = onHorizontalDragUpdate ..onUpdate = onHorizontalDragUpdate
..onEnd = onHorizontalDragEnd ..onEnd = onHorizontalDragEnd
..onCancel = onHorizontalDragCancel; ..onCancel = onHorizontalDragCancel
..dragStartBehavior = dragStartBehavior;
}, },
); );
} }
...@@ -457,7 +478,8 @@ class GestureDetector extends StatelessWidget { ...@@ -457,7 +478,8 @@ class GestureDetector extends StatelessWidget {
..onStart = onPanStart ..onStart = onPanStart
..onUpdate = onPanUpdate ..onUpdate = onPanUpdate
..onEnd = onPanEnd ..onEnd = onPanEnd
..onCancel = onPanCancel; ..onCancel = onPanCancel
..dragStartBehavior = dragStartBehavior;
}, },
); );
} }
...@@ -497,6 +519,11 @@ class GestureDetector extends StatelessWidget { ...@@ -497,6 +519,11 @@ class GestureDetector extends StatelessWidget {
child: child, child: child,
); );
} }
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(EnumProperty<DragStartBehavior>('startBehavior', dragStartBehavior));
}
} }
/// A widget that detects gestures described by the given gesture /// A widget that detects gestures described by the given gesture
...@@ -550,7 +577,7 @@ class RawGestureDetector extends StatefulWidget { ...@@ -550,7 +577,7 @@ class RawGestureDetector extends StatefulWidget {
this.child, this.child,
this.gestures = const <Type, GestureRecognizerFactory>{}, this.gestures = const <Type, GestureRecognizerFactory>{},
this.behavior, this.behavior,
this.excludeFromSemantics = false this.excludeFromSemantics = false,
}) : assert(gestures != null), }) : assert(gestures != null),
assert(excludeFromSemantics != null), assert(excludeFromSemantics != null),
super(key: key); super(key: key);
......
...@@ -10,6 +10,7 @@ import 'package:flutter/painting.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/painting.dart';
import 'package:flutter/physics.dart'; import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
...@@ -51,7 +52,7 @@ typedef NestedScrollViewHeaderSliversBuilder = List<Widget> Function(BuildContex ...@@ -51,7 +52,7 @@ typedef NestedScrollViewHeaderSliversBuilder = List<Widget> Function(BuildContex
/// in the opposite direction (e.g. allowing the user to swipe horizontally /// in the opposite direction (e.g. allowing the user to swipe horizontally
/// between the pages represented by the tabs, while the list scrolls /// between the pages represented by the tabs, while the list scrolls
/// vertically), then any list inside that [TabBarView] would not interact with /// vertically), then any list inside that [TabBarView] would not interact with
/// the outer [ScrollView]. For example, flinging the inner list to scroll to /// the outer [ScrollView]. For example, flinginsg the inner list to scroll to
/// the top would not cause a collapsed [SliverAppBar] in the outer [ScrollView] /// the top would not cause a collapsed [SliverAppBar] in the outer [ScrollView]
/// to expand. /// to expand.
/// ///
...@@ -188,6 +189,7 @@ class NestedScrollView extends StatefulWidget { ...@@ -188,6 +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.start,
}) : assert(scrollDirection != null), }) : assert(scrollDirection != null),
assert(reverse != null), assert(reverse != null),
assert(headerSliverBuilder != null), assert(headerSliverBuilder != null),
...@@ -252,6 +254,9 @@ class NestedScrollView extends StatefulWidget { ...@@ -252,6 +254,9 @@ class NestedScrollView extends StatefulWidget {
/// the [PrimaryScrollController] provided by the [NestedScrollView]. /// the [PrimaryScrollController] provided by the [NestedScrollView].
final Widget body; final Widget body;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// Returns the [SliverOverlapAbsorberHandle] of the nearest ancestor /// Returns the [SliverOverlapAbsorberHandle] of the nearest ancestor
/// [NestedScrollView]. /// [NestedScrollView].
/// ///
...@@ -338,6 +343,7 @@ class _NestedScrollViewState extends State<NestedScrollView> { ...@@ -338,6 +343,7 @@ class _NestedScrollViewState extends State<NestedScrollView> {
builder: (BuildContext context) { builder: (BuildContext context) {
_lastHasScrolledBody = _coordinator.hasScrolledBody; _lastHasScrolledBody = _coordinator.hasScrolledBody;
return _NestedScrollViewCustomScrollView( return _NestedScrollViewCustomScrollView(
dragStartBehavior: widget.dragStartBehavior,
scrollDirection: widget.scrollDirection, scrollDirection: widget.scrollDirection,
reverse: widget.reverse, reverse: widget.reverse,
physics: widget.physics != null physics: widget.physics != null
...@@ -365,12 +371,14 @@ class _NestedScrollViewCustomScrollView extends CustomScrollView { ...@@ -365,12 +371,14 @@ 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.start,
}) : super( }) : super(
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
reverse: reverse, reverse: reverse,
physics: physics, physics: physics,
controller: controller, controller: controller,
slivers: slivers, slivers: slivers,
dragStartBehavior: dragStartBehavior,
); );
final SliverOverlapAbsorberHandle handle; final SliverOverlapAbsorberHandle handle;
......
...@@ -7,6 +7,7 @@ import 'dart:math' as math; ...@@ -7,6 +7,7 @@ import 'dart:math' as math;
import 'package:flutter/physics.dart'; import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'basic.dart'; import 'basic.dart';
import 'debug.dart'; import 'debug.dart';
...@@ -423,6 +424,7 @@ class PageView extends StatefulWidget { ...@@ -423,6 +424,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.start,
}) : controller = controller ?? _defaultPageController, }) : controller = controller ?? _defaultPageController,
childrenDelegate = SliverChildListDelegate(children), childrenDelegate = SliverChildListDelegate(children),
super(key: key); super(key: key);
...@@ -449,6 +451,7 @@ class PageView extends StatefulWidget { ...@@ -449,6 +451,7 @@ class PageView extends StatefulWidget {
this.onPageChanged, this.onPageChanged,
@required IndexedWidgetBuilder itemBuilder, @required IndexedWidgetBuilder itemBuilder,
int itemCount, int itemCount,
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);
...@@ -464,6 +467,7 @@ class PageView extends StatefulWidget { ...@@ -464,6 +467,7 @@ class PageView extends StatefulWidget {
this.pageSnapping = true, this.pageSnapping = true,
this.onPageChanged, this.onPageChanged,
@required this.childrenDelegate, @required this.childrenDelegate,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(childrenDelegate != null), }) : assert(childrenDelegate != null),
controller = controller ?? _defaultPageController, controller = controller ?? _defaultPageController,
super(key: key); super(key: key);
...@@ -516,6 +520,9 @@ class PageView extends StatefulWidget { ...@@ -516,6 +520,9 @@ class PageView extends StatefulWidget {
/// respectively. /// respectively.
final SliverChildDelegate childrenDelegate; final SliverChildDelegate childrenDelegate;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
@override @override
_PageViewState createState() => _PageViewState(); _PageViewState createState() => _PageViewState();
} }
...@@ -562,6 +569,7 @@ class _PageViewState extends State<PageView> { ...@@ -562,6 +569,7 @@ class _PageViewState extends State<PageView> {
return false; return false;
}, },
child: Scrollable( child: Scrollable(
dragStartBehavior: widget.dragStartBehavior,
axisDirection: axisDirection, axisDirection: axisDirection,
controller: widget.controller, controller: widget.controller,
physics: physics, physics: physics,
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart';
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
...@@ -60,8 +61,10 @@ abstract class ScrollView extends StatelessWidget { ...@@ -60,8 +61,10 @@ abstract class ScrollView extends StatelessWidget {
this.shrinkWrap = false, this.shrinkWrap = false,
this.cacheExtent, this.cacheExtent,
this.semanticChildCount, this.semanticChildCount,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(reverse != null), }) : assert(reverse != null),
assert(shrinkWrap != null), assert(shrinkWrap != null),
assert(dragStartBehavior != null),
assert(!(controller != null && primary == true), assert(!(controller != null && primary == true),
'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. ' 'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. '
'You cannot both set primary to true and pass an explicit controller.' 'You cannot both set primary to true and pass an explicit controller.'
...@@ -187,6 +190,9 @@ abstract class ScrollView extends StatelessWidget { ...@@ -187,6 +190,9 @@ abstract class ScrollView extends StatelessWidget {
/// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property. /// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property.
final int semanticChildCount; final int semanticChildCount;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// Returns the [AxisDirection] in which the scroll view scrolls. /// Returns the [AxisDirection] in which the scroll view scrolls.
/// ///
/// Combines the [scrollDirection] with the [reverse] boolean to obtain the /// Combines the [scrollDirection] with the [reverse] boolean to obtain the
...@@ -246,6 +252,7 @@ abstract class ScrollView extends StatelessWidget { ...@@ -246,6 +252,7 @@ abstract class ScrollView extends StatelessWidget {
? PrimaryScrollController.of(context) ? PrimaryScrollController.of(context)
: controller; : controller;
final Scrollable scrollable = Scrollable( final Scrollable scrollable = Scrollable(
dragStartBehavior: dragStartBehavior,
axisDirection: axisDirection, axisDirection: axisDirection,
controller: scrollController, controller: scrollController,
physics: physics, physics: physics,
...@@ -397,6 +404,7 @@ class CustomScrollView extends ScrollView { ...@@ -397,6 +404,7 @@ class CustomScrollView extends ScrollView {
double cacheExtent, double cacheExtent,
this.slivers = const <Widget>[], this.slivers = const <Widget>[],
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super( }) : super(
key: key, key: key,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
...@@ -407,6 +415,7 @@ class CustomScrollView extends ScrollView { ...@@ -407,6 +415,7 @@ class CustomScrollView extends ScrollView {
shrinkWrap: shrinkWrap, shrinkWrap: shrinkWrap,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount, semanticChildCount: semanticChildCount,
dragStartBehavior: dragStartBehavior,
); );
/// The slivers to place inside the viewport. /// The slivers to place inside the viewport.
...@@ -439,6 +448,7 @@ abstract class BoxScrollView extends ScrollView { ...@@ -439,6 +448,7 @@ abstract class BoxScrollView extends ScrollView {
this.padding, this.padding,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : super( }) : super(
key: key, key: key,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
...@@ -449,6 +459,7 @@ abstract class BoxScrollView extends ScrollView { ...@@ -449,6 +459,7 @@ abstract class BoxScrollView extends ScrollView {
shrinkWrap: shrinkWrap, shrinkWrap: shrinkWrap,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount, semanticChildCount: semanticChildCount,
dragStartBehavior: dragStartBehavior,
); );
/// The amount of space by which to inset the children. /// The amount of space by which to inset the children.
...@@ -739,6 +750,7 @@ class ListView extends BoxScrollView { ...@@ -739,6 +750,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.start,
}) : childrenDelegate = SliverChildListDelegate( }) : childrenDelegate = SliverChildListDelegate(
children, children,
addAutomaticKeepAlives: addAutomaticKeepAlives, addAutomaticKeepAlives: addAutomaticKeepAlives,
...@@ -755,6 +767,7 @@ class ListView extends BoxScrollView { ...@@ -755,6 +767,7 @@ class ListView extends BoxScrollView {
padding: padding, padding: padding,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount ?? children.length, semanticChildCount: semanticChildCount ?? children.length,
dragStartBehavior: dragStartBehavior,
); );
/// Creates a scrollable, linear array of widgets that are created on demand. /// Creates a scrollable, linear array of widgets that are created on demand.
...@@ -800,6 +813,7 @@ class ListView extends BoxScrollView { ...@@ -800,6 +813,7 @@ class ListView extends BoxScrollView {
bool addSemanticIndexes = true, bool addSemanticIndexes = true,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : childrenDelegate = SliverChildBuilderDelegate( }) : childrenDelegate = SliverChildBuilderDelegate(
itemBuilder, itemBuilder,
childCount: itemCount, childCount: itemCount,
...@@ -817,6 +831,7 @@ class ListView extends BoxScrollView { ...@@ -817,6 +831,7 @@ class ListView extends BoxScrollView {
padding: padding, padding: padding,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount ?? itemCount, semanticChildCount: semanticChildCount ?? itemCount,
dragStartBehavior: dragStartBehavior,
); );
/// Creates a fixed-length scrollable linear array of list "items" separated /// Creates a fixed-length scrollable linear array of list "items" separated
...@@ -1250,6 +1265,7 @@ class GridView extends BoxScrollView { ...@@ -1250,6 +1265,7 @@ class GridView extends BoxScrollView {
@required this.childrenDelegate, @required this.childrenDelegate,
double cacheExtent, double cacheExtent,
int semanticChildCount, int semanticChildCount,
DragStartBehavior dragStartBehavior = DragStartBehavior.start,
}) : assert(gridDelegate != null), }) : assert(gridDelegate != null),
assert(childrenDelegate != null), assert(childrenDelegate != null),
super( super(
...@@ -1263,6 +1279,7 @@ class GridView extends BoxScrollView { ...@@ -1263,6 +1279,7 @@ class GridView extends BoxScrollView {
padding: padding, padding: padding,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount, semanticChildCount: semanticChildCount,
dragStartBehavior: dragStartBehavior,
); );
/// Creates a scrollable, 2D array of widgets with a fixed number of tiles in /// Creates a scrollable, 2D array of widgets with a fixed number of tiles in
...@@ -1298,6 +1315,7 @@ class GridView extends BoxScrollView { ...@@ -1298,6 +1315,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.start,
}) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount( }) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount, crossAxisCount: crossAxisCount,
mainAxisSpacing: mainAxisSpacing, mainAxisSpacing: mainAxisSpacing,
...@@ -1320,6 +1338,7 @@ class GridView extends BoxScrollView { ...@@ -1320,6 +1338,7 @@ class GridView extends BoxScrollView {
padding: padding, padding: padding,
cacheExtent: cacheExtent, cacheExtent: cacheExtent,
semanticChildCount: semanticChildCount ?? children.length, semanticChildCount: semanticChildCount ?? children.length,
dragStartBehavior: dragStartBehavior,
); );
/// Creates a scrollable, 2D array of widgets with tiles that each have a /// Creates a scrollable, 2D array of widgets with tiles that each have a
...@@ -1354,6 +1373,7 @@ class GridView extends BoxScrollView { ...@@ -1354,6 +1373,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.start,
}) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent( }) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent, maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: mainAxisSpacing, mainAxisSpacing: mainAxisSpacing,
...@@ -1375,6 +1395,7 @@ class GridView extends BoxScrollView { ...@@ -1375,6 +1395,7 @@ class GridView extends BoxScrollView {
shrinkWrap: shrinkWrap, shrinkWrap: shrinkWrap,
padding: padding, padding: padding,
semanticChildCount: semanticChildCount ?? children.length, semanticChildCount: semanticChildCount ?? children.length,
dragStartBehavior: dragStartBehavior,
); );
/// A delegate that controls the layout of the children within the [GridView]. /// A delegate that controls the layout of the children within the [GridView].
......
...@@ -81,7 +81,9 @@ class Scrollable extends StatefulWidget { ...@@ -81,7 +81,9 @@ class Scrollable extends StatefulWidget {
@required this.viewportBuilder, @required this.viewportBuilder,
this.excludeFromSemantics = false, this.excludeFromSemantics = false,
this.semanticChildCount, this.semanticChildCount,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(axisDirection != null), }) : assert(axisDirection != null),
assert(dragStartBehavior != null),
assert(viewportBuilder != null), assert(viewportBuilder != null),
assert(excludeFromSemantics != null), assert(excludeFromSemantics != null),
super (key: key); super (key: key);
...@@ -180,6 +182,25 @@ class Scrollable extends StatefulWidget { ...@@ -180,6 +182,25 @@ class Scrollable extends StatefulWidget {
/// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property. /// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property.
final int semanticChildCount; final int semanticChildCount;
/// {@template flutter.widgets.scrollable.dragStartBehavior}
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], scrolling drag behavior will
/// begin upon the detection of a drag gesture. If set to
/// [DragStartBehavior.down] it will begin when a down event is first detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
/// {@endtemplate}
final DragStartBehavior dragStartBehavior;
/// The axis along which the scroll view scrolls. /// The axis along which the scroll view scrolls.
/// ///
/// Determined by the [axisDirection]. /// Determined by the [axisDirection].
...@@ -391,7 +412,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin ...@@ -391,7 +412,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
..onCancel = _handleDragCancel ..onCancel = _handleDragCancel
..minFlingDistance = _physics?.minFlingDistance ..minFlingDistance = _physics?.minFlingDistance
..minFlingVelocity = _physics?.minFlingVelocity ..minFlingVelocity = _physics?.minFlingVelocity
..maxFlingVelocity = _physics?.maxFlingVelocity; ..maxFlingVelocity = _physics?.maxFlingVelocity
..dragStartBehavior = widget.dragStartBehavior;
}, },
), ),
}; };
...@@ -409,7 +431,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin ...@@ -409,7 +431,8 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin
..onCancel = _handleDragCancel ..onCancel = _handleDragCancel
..minFlingDistance = _physics?.minFlingDistance ..minFlingDistance = _physics?.minFlingDistance
..minFlingVelocity = _physics?.minFlingVelocity ..minFlingVelocity = _physics?.minFlingVelocity
..maxFlingVelocity = _physics?.maxFlingVelocity; ..maxFlingVelocity = _physics?.maxFlingVelocity
..dragStartBehavior = widget.dragStartBehavior;
}, },
), ),
}; };
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
...@@ -192,7 +193,9 @@ class SingleChildScrollView extends StatelessWidget { ...@@ -192,7 +193,9 @@ class SingleChildScrollView extends StatelessWidget {
this.physics, this.physics,
this.controller, this.controller,
this.child, this.child,
this.dragStartBehavior = DragStartBehavior.start,
}) : assert(scrollDirection != null), }) : assert(scrollDirection != null),
assert(dragStartBehavior != null),
assert(!(controller != null && primary == true), assert(!(controller != null && primary == true),
'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. ' 'Primary ScrollViews obtain their ScrollController via inheritance from a PrimaryScrollController widget. '
'You cannot both set primary to true and pass an explicit controller.' 'You cannot both set primary to true and pass an explicit controller.'
...@@ -259,6 +262,9 @@ class SingleChildScrollView extends StatelessWidget { ...@@ -259,6 +262,9 @@ class SingleChildScrollView extends StatelessWidget {
/// {@macro flutter.widgets.child} /// {@macro flutter.widgets.child}
final Widget child; final Widget child;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
AxisDirection _getDirection(BuildContext context) { AxisDirection _getDirection(BuildContext context) {
return getAxisDirectionFromAxisReverseAndDirectionality(context, scrollDirection, reverse); return getAxisDirectionFromAxisReverseAndDirectionality(context, scrollDirection, reverse);
} }
...@@ -273,6 +279,7 @@ class SingleChildScrollView extends StatelessWidget { ...@@ -273,6 +279,7 @@ class SingleChildScrollView extends StatelessWidget {
? PrimaryScrollController.of(context) ? PrimaryScrollController.of(context)
: controller; : controller;
final Scrollable scrollable = Scrollable( final Scrollable scrollable = Scrollable(
dragStartBehavior: dragStartBehavior,
axisDirection: axisDirection, axisDirection: axisDirection,
controller: scrollController, controller: scrollController,
physics: physics, physics: physics,
......
...@@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart' show kDoubleTapTimeout, kDoubleTapSlop; ...@@ -8,6 +8,7 @@ import 'package:flutter/gestures.dart' show kDoubleTapTimeout, kDoubleTapSlop;
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'basic.dart'; import 'basic.dart';
import 'container.dart'; import 'container.dart';
...@@ -229,6 +230,7 @@ class TextSelectionOverlay { ...@@ -229,6 +230,7 @@ class TextSelectionOverlay {
@required this.renderObject, @required this.renderObject,
this.selectionControls, this.selectionControls,
this.selectionDelegate, this.selectionDelegate,
this.dragStartBehavior = DragStartBehavior.start,
}): assert(value != null), }): assert(value != null),
assert(context != null), assert(context != null),
_value = value { _value = value {
...@@ -263,6 +265,23 @@ class TextSelectionOverlay { ...@@ -263,6 +265,23 @@ class TextSelectionOverlay {
/// text field. /// text field.
final TextSelectionDelegate selectionDelegate; final TextSelectionDelegate selectionDelegate;
/// Determines the way that drag start behavior is handled.
///
/// If set to [DragStartBehavior.start], handle drag behavior will
/// begin upon the detection of a drag gesture. If set to
/// [DragStartBehavior.down] it will begin when a down event is first detected.
///
/// In general, setting this to [DragStartBehavior.start] will make drag
/// animation smoother and setting it to [DragStartBehavior.down] will make
/// drag behavior feel slightly more reactive.
///
/// By default, the drag start behavior is [DragStartBehavior.start].
///
/// See also:
///
/// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
final DragStartBehavior dragStartBehavior;
/// Controls the fade-in animations. /// Controls the fade-in animations.
static const Duration _fadeDuration = Duration(milliseconds: 150); static const Duration _fadeDuration = Duration(milliseconds: 150);
AnimationController _handleController; AnimationController _handleController;
...@@ -365,9 +384,8 @@ class TextSelectionOverlay { ...@@ -365,9 +384,8 @@ class TextSelectionOverlay {
Widget _buildHandle(BuildContext context, _TextSelectionHandlePosition position) { Widget _buildHandle(BuildContext context, _TextSelectionHandlePosition position) {
if ((_selection.isCollapsed && position == _TextSelectionHandlePosition.end) || if ((_selection.isCollapsed && position == _TextSelectionHandlePosition.end) ||
selectionControls == null) selectionControls == null)
return Container(); // hide the second handle when collapsed return Container(); // hide the second handle when collapsed
return FadeTransition( return FadeTransition(
opacity: _handleOpacity, opacity: _handleOpacity,
child: _TextSelectionHandleOverlay( child: _TextSelectionHandleOverlay(
...@@ -378,6 +396,7 @@ class TextSelectionOverlay { ...@@ -378,6 +396,7 @@ class TextSelectionOverlay {
selection: _selection, selection: _selection,
selectionControls: selectionControls, selectionControls: selectionControls,
position: position, position: position,
dragStartBehavior: dragStartBehavior,
) )
); );
} }
...@@ -447,7 +466,8 @@ class _TextSelectionHandleOverlay extends StatefulWidget { ...@@ -447,7 +466,8 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
@required this.renderObject, @required this.renderObject,
@required this.onSelectionHandleChanged, @required this.onSelectionHandleChanged,
@required this.onSelectionHandleTapped, @required this.onSelectionHandleTapped,
@required this.selectionControls @required this.selectionControls,
this.dragStartBehavior = DragStartBehavior.start,
}) : super(key: key); }) : super(key: key);
final TextSelection selection; final TextSelection selection;
...@@ -457,6 +477,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget { ...@@ -457,6 +477,7 @@ class _TextSelectionHandleOverlay extends StatefulWidget {
final ValueChanged<TextSelection> onSelectionHandleChanged; final ValueChanged<TextSelection> onSelectionHandleChanged;
final VoidCallback onSelectionHandleTapped; final VoidCallback onSelectionHandleTapped;
final TextSelectionControls selectionControls; final TextSelectionControls selectionControls;
final DragStartBehavior dragStartBehavior;
@override @override
_TextSelectionHandleOverlayState createState() => _TextSelectionHandleOverlayState(); _TextSelectionHandleOverlayState createState() => _TextSelectionHandleOverlayState();
...@@ -528,6 +549,7 @@ class _TextSelectionHandleOverlayState extends State<_TextSelectionHandleOverlay ...@@ -528,6 +549,7 @@ class _TextSelectionHandleOverlayState extends State<_TextSelectionHandleOverlay
link: widget.layerLink, link: widget.layerLink,
showWhenUnlinked: false, showWhenUnlinked: false,
child: GestureDetector( child: GestureDetector(
dragStartBehavior: widget.dragStartBehavior,
onPanStart: _handleDragStart, onPanStart: _handleDragStart,
onPanUpdate: _handleDragUpdate, onPanUpdate: _handleDragUpdate,
onTap: _handleTap, onTap: _handleTap,
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
void main() { void main() {
testWidgets('Switch can toggle on tap', (WidgetTester tester) async { testWidgets('Switch can toggle on tap', (WidgetTester tester) async {
...@@ -18,6 +19,7 @@ void main() { ...@@ -18,6 +19,7 @@ void main() {
child: CupertinoSwitch( child: CupertinoSwitch(
key: switchKey, key: switchKey,
value: value, value: value,
dragStartBehavior: DragStartBehavior.down,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
value = newValue; value = newValue;
...@@ -46,6 +48,7 @@ void main() { ...@@ -46,6 +48,7 @@ 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;
...@@ -79,6 +82,88 @@ void main() { ...@@ -79,6 +82,88 @@ void main() {
expect(value, isFalse); expect(value, isFalse);
}); });
testWidgets('Switch can drag with dragStartBehavior', (WidgetTester tester) async {
bool value = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Center(
child: CupertinoSwitch(
value: value,
dragStartBehavior: DragStartBehavior.down,
onChanged: (bool newValue) {
setState(() {
value = newValue;
});
},
),
);
},
),
),
);
expect(value, isFalse);
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
expect(value, isFalse);
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
expect(value, isTrue);
await tester.pump();
await tester.drag(find.byType(CupertinoSwitch), const Offset(30.0, 0.0));
expect(value, isTrue);
await tester.pump();
await tester.drag(find.byType(CupertinoSwitch), const Offset(-30.0, 0.0));
expect(value, isFalse);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Center(
child: CupertinoSwitch(
value: value,
dragStartBehavior: DragStartBehavior.start,
onChanged: (bool newValue) {
setState(() {
value = newValue;
});
},
),
);
},
),
),
);
await tester.pumpAndSettle();
final Rect switchRect = tester.getRect(find.byType(CupertinoSwitch));
TestGesture gesture = await tester.startGesture(switchRect.center);
// We have to execute the drag in two frames because the first update will
// just set the start position.
await gesture.moveBy(const Offset(20.0, 0.0));
await gesture.moveBy(const Offset(20.0, 0.0));
expect(value, isTrue);
await gesture.up();
await tester.pump();
gesture = await tester.startGesture(switchRect.center);
await gesture.moveBy(const Offset(20.0, 0.0));
await gesture.moveBy(const Offset(20.0, 0.0));
expect(value, isTrue);
await gesture.up();
await tester.pump();
gesture = await tester.startGesture(switchRect.center);
await gesture.moveBy(const Offset(-20.0, 0.0));
await gesture.moveBy(const Offset(-20.0, 0.0));
expect(value, isFalse);
});
testWidgets('Switch can drag (RTL)', (WidgetTester tester) async { testWidgets('Switch can drag (RTL)', (WidgetTester tester) async {
bool value = false; bool value = false;
...@@ -90,6 +175,7 @@ void main() { ...@@ -90,6 +175,7 @@ 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;
......
...@@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart'; import 'feedback_tester.dart';
...@@ -46,8 +47,10 @@ void _tests() { ...@@ -46,8 +47,10 @@ void _tests() {
return Container( return Container(
width: 400.0, width: 400.0,
child: SingleChildScrollView( child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
child: Material( child: Material(
child: MonthPicker( child: MonthPicker(
dragStartBehavior: DragStartBehavior.down,
firstDate: DateTime(0), firstDate: DateTime(0),
lastDate: DateTime(9999), lastDate: DateTime(9999),
key: _datePickerKey, key: _datePickerKey,
...@@ -63,7 +66,7 @@ void _tests() { ...@@ -63,7 +66,7 @@ void _tests() {
); );
}, },
), ),
) ),
); );
expect(_selectedDate, equals(DateTime(2016, DateTime.july, 26))); expect(_selectedDate, equals(DateTime(2016, DateTime.july, 26)));
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
...@@ -164,6 +165,7 @@ void main() { ...@@ -164,6 +165,7 @@ void main() {
link: LayerLink(), link: LayerLink(),
child: ListView( child: ListView(
addAutomaticKeepAlives: keepAlive, addAutomaticKeepAlives: keepAlive,
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
Container(height: 500.0, child: InkWell(onTap: () { }, child: const Placeholder())), Container(height: 500.0, child: InkWell(onTap: () { }, child: const Placeholder())),
Container(height: 500.0), Container(height: 500.0),
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'data_table_test_utils.dart'; import 'data_table_test_utils.dart';
...@@ -248,26 +249,29 @@ void main() { ...@@ -248,26 +249,29 @@ void main() {
testWidgets('PaginatedDataTable footer scrolls', (WidgetTester tester) async { testWidgets('PaginatedDataTable footer scrolls', (WidgetTester tester) async {
final TestDataSource source = TestDataSource(); final TestDataSource source = TestDataSource();
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(
home: Align( MaterialApp(
alignment: Alignment.topLeft, home: Align(
child: SizedBox( alignment: Alignment.topLeft,
width: 100.0, child: SizedBox(
child: PaginatedDataTable( width: 100.0,
header: const Text('HEADER'), child: PaginatedDataTable(
source: source, header: const Text('HEADER'),
rowsPerPage: 5, source: source,
availableRowsPerPage: const <int>[ 5 ], rowsPerPage: 5,
onRowsPerPageChanged: (int rowsPerPage) { }, dragStartBehavior: DragStartBehavior.down,
columns: const <DataColumn>[ availableRowsPerPage: const <int>[ 5 ],
DataColumn(label: Text('COL1')), onRowsPerPageChanged: (int rowsPerPage) { },
DataColumn(label: Text('COL2')), columns: const <DataColumn>[
DataColumn(label: Text('COL3')), DataColumn(label: Text('COL1')),
], DataColumn(label: Text('COL2')),
DataColumn(label: Text('COL3')),
],
),
), ),
), ),
), ),
)); );
expect(find.text('Rows per page:'), findsOneWidget); expect(find.text('Rows per page:'), findsOneWidget);
expect(tester.getTopLeft(find.text('Rows per page:')).dx, lessThan(0.0)); // off screen expect(tester.getTopLeft(find.text('Rows per page:')).dx, lessThan(0.0)); // off screen
await tester.dragFrom( await tester.dragFrom(
......
...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
...@@ -201,6 +202,7 @@ void main() { ...@@ -201,6 +202,7 @@ void main() {
drawer: Drawer( drawer: Drawer(
key: drawerKey, key: drawerKey,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
controller: scrollOffset, controller: scrollOffset,
children: List<Widget>.generate(10, children: List<Widget>.generate(10,
(int index) => SizedBox(height: 100.0, child: Text('D$index')) (int index) => SizedBox(height: 100.0, child: Text('D$index'))
...@@ -630,6 +632,7 @@ void main() { ...@@ -630,6 +632,7 @@ void main() {
viewInsets: EdgeInsets.only(bottom: 200.0), viewInsets: EdgeInsets.only(bottom: 200.0),
), ),
child: Scaffold( child: Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size(11.0, 13.0), preferredSize: const Size(11.0, 13.0),
child: Container( child: Container(
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart';
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
...@@ -25,6 +25,7 @@ void main() { ...@@ -25,6 +25,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
key: switchKey, key: switchKey,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
...@@ -54,6 +55,7 @@ void main() { ...@@ -54,6 +55,7 @@ void main() {
child: Material( child: Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: true, value: true,
onChanged: (bool newValue) {}, onChanged: (bool newValue) {},
), ),
...@@ -73,6 +75,7 @@ void main() { ...@@ -73,6 +75,7 @@ void main() {
child: Material( child: Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: true, value: true,
onChanged: (bool newValue) {}, onChanged: (bool newValue) {},
), ),
...@@ -96,6 +99,7 @@ void main() { ...@@ -96,6 +99,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
...@@ -131,6 +135,93 @@ void main() { ...@@ -131,6 +135,93 @@ void main() {
expect(value, isFalse); expect(value, isFalse);
}); });
testWidgets('Switch can drag with dragStartBehavior', (WidgetTester tester) async {
bool value = false;
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value,
onChanged: (bool newValue) {
setState(() {
value = newValue;
}
);
}
),
),
);
},
),
),
);
expect(value, isFalse);
await tester.drag(find.byType(Switch), const Offset(-30.0, 0.0));
expect(value, isFalse);
await tester.drag(find.byType(Switch), const Offset(30.0, 0.0));
expect(value, isTrue);
await tester.pump();
await tester.drag(find.byType(Switch), const Offset(30.0, 0.0));
expect(value, isTrue);
await tester.pump();
await tester.drag(find.byType(Switch), const Offset(-30.0, 0.0));
expect(value, isFalse);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Material(
child: Center(
child: Switch(
dragStartBehavior: DragStartBehavior.start,
value: value,
onChanged: (bool newValue) {
setState(() {
value = newValue;
});
}
),
),
);
},
),
),
);
await tester.pumpAndSettle();
final Rect switchRect = tester.getRect(find.byType(Switch));
TestGesture gesture = await tester.startGesture(switchRect.center);
// We have to execute the drag in two frames because the first update will
// just set the start position.
await gesture.moveBy(const Offset(20.0, 0.0));
await gesture.moveBy(const Offset(20.0, 0.0));
expect(value, isTrue);
await gesture.up();
await tester.pump();
gesture = await tester.startGesture(switchRect.center);
await gesture.moveBy(const Offset(20.0, 0.0));
await gesture.moveBy(const Offset(20.0, 0.0));
expect(value, isTrue);
await gesture.up();
await tester.pump();
gesture = await tester.startGesture(switchRect.center);
await gesture.moveBy(const Offset(-20.0, 0.0));
await gesture.moveBy(const Offset(-20.0, 0.0));
expect(value, isFalse);
});
testWidgets('Switch can drag (RTL)', (WidgetTester tester) async { testWidgets('Switch can drag (RTL)', (WidgetTester tester) async {
bool value = false; bool value = false;
...@@ -142,6 +233,7 @@ void main() { ...@@ -142,6 +233,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
...@@ -185,6 +277,7 @@ void main() { ...@@ -185,6 +277,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
...@@ -306,6 +399,7 @@ void main() { ...@@ -306,6 +399,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
...@@ -365,6 +459,7 @@ void main() { ...@@ -365,6 +459,7 @@ void main() {
return Material( return Material(
child: Center( child: Center(
child: Switch( child: Switch(
dragStartBehavior: DragStartBehavior.down,
value: value, value: value,
onChanged: (bool newValue) { onChanged: (bool newValue) {
setState(() { setState(() {
......
...@@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; ...@@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import 'feedback_tester.dart'; import 'feedback_tester.dart';
...@@ -501,9 +502,12 @@ void main() { ...@@ -501,9 +502,12 @@ void main() {
final TextEditingController controller = TextEditingController(); final TextEditingController controller = TextEditingController();
await tester.pumpWidget( await tester.pumpWidget(
overlay( MaterialApp(
child: TextField( home: Material(
controller: controller, child: TextField(
dragStartBehavior: DragStartBehavior.down,
controller: controller,
),
), ),
), ),
); );
...@@ -542,7 +546,7 @@ void main() { ...@@ -542,7 +546,7 @@ void main() {
await tester.pump(); await tester.pump();
expect(controller.selection.baseOffset, selection.baseOffset); expect(controller.selection.baseOffset, selection.baseOffset);
expect(controller.selection.extentOffset, selection.extentOffset+2); expect(controller.selection.extentOffset, selection.extentOffset);
// Drag the left handle 2 letters to the left. // Drag the left handle 2 letters to the left.
handlePos = endpoints[0].point + const Offset(-1.0, 1.0); handlePos = endpoints[0].point + const Offset(-1.0, 1.0);
...@@ -554,8 +558,8 @@ void main() { ...@@ -554,8 +558,8 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pump(); await tester.pump();
expect(controller.selection.baseOffset, selection.baseOffset-2); expect(controller.selection.baseOffset, selection.baseOffset);
expect(controller.selection.extentOffset, selection.extentOffset+2); expect(controller.selection.extentOffset, selection.extentOffset);
}); });
testWidgets('Can use selection toolbar', (WidgetTester tester) async { testWidgets('Can use selection toolbar', (WidgetTester tester) async {
...@@ -826,6 +830,7 @@ void main() { ...@@ -826,6 +830,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
overlay( overlay(
child: TextField( child: TextField(
dragStartBehavior: DragStartBehavior.down,
controller: controller, controller: controller,
style: const TextStyle(color: Colors.black, fontSize: 34.0), style: const TextStyle(color: Colors.black, fontSize: 34.0),
maxLines: 3, maxLines: 3,
...@@ -909,6 +914,7 @@ void main() { ...@@ -909,6 +914,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
overlay( overlay(
child: TextField( child: TextField(
dragStartBehavior: DragStartBehavior.down,
key: textFieldKey, key: textFieldKey,
controller: controller, controller: controller,
style: const TextStyle(color: Colors.black, fontSize: 34.0), style: const TextStyle(color: Colors.black, fontSize: 34.0),
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
class Leaf extends StatefulWidget { class Leaf extends StatefulWidget {
const Leaf({ Key key, this.child }) : super(key: key); const Leaf({ Key key, this.child }) : super(key: key);
...@@ -476,6 +477,7 @@ void main() { ...@@ -476,6 +477,7 @@ void main() {
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
dragStartBehavior: DragStartBehavior.down,
addSemanticIndexes: false, addSemanticIndexes: false,
itemCount: 50, itemCount: 50,
itemBuilder: (BuildContext context, int index){ itemBuilder: (BuildContext context, int index){
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
const double itemExtent = 100.0; const double itemExtent = 100.0;
Axis scrollDirection = Axis.vertical; Axis scrollDirection = Axis.vertical;
...@@ -21,6 +22,7 @@ Widget buildTest({ double startToEndThreshold, TextDirection textDirection = Tex ...@@ -21,6 +22,7 @@ Widget buildTest({ double startToEndThreshold, TextDirection textDirection = Tex
builder: (BuildContext context, StateSetter setState) { builder: (BuildContext context, StateSetter setState) {
Widget buildDismissibleItem(int item) { Widget buildDismissibleItem(int item) {
return Dismissible( return Dismissible(
dragStartBehavior: DragStartBehavior.down,
key: ValueKey<int>(item), key: ValueKey<int>(item),
direction: dismissDirection, direction: dismissDirection,
onDismissed: (DismissDirection direction) { onDismissed: (DismissDirection direction) {
...@@ -49,6 +51,7 @@ Widget buildTest({ double startToEndThreshold, TextDirection textDirection = Tex ...@@ -49,6 +51,7 @@ Widget buildTest({ double startToEndThreshold, TextDirection textDirection = Tex
return Container( return Container(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
scrollDirection: scrollDirection, scrollDirection: scrollDirection,
itemExtent: itemExtent, itemExtent: itemExtent,
children: <int>[0, 1, 2, 3, 4] children: <int>[0, 1, 2, 3, 4]
...@@ -199,6 +202,7 @@ class Test1215DismissibleWidget extends StatelessWidget { ...@@ -199,6 +202,7 @@ class Test1215DismissibleWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dismissible( return Dismissible(
dragStartBehavior: DragStartBehavior.down,
key: ObjectKey(text), key: ObjectKey(text),
child: AspectRatio( child: AspectRatio(
aspectRatio: 1.0, aspectRatio: 1.0,
......
...@@ -383,6 +383,7 @@ void main() { ...@@ -383,6 +383,7 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: ListView( home: ListView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
DragTarget<int>( DragTarget<int>(
builder: (BuildContext context, List<int> data, List<dynamic> rejects) { builder: (BuildContext context, List<int> data, List<dynamic> rejects) {
...@@ -489,6 +490,7 @@ void main() { ...@@ -489,6 +490,7 @@ void main() {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: ListView( home: ListView(
dragStartBehavior: DragStartBehavior.down,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: <Widget>[ children: <Widget>[
DragTarget<int>( DragTarget<int>(
......
...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart'; ...@@ -9,6 +9,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'semantics_tester.dart'; import 'semantics_tester.dart';
...@@ -82,6 +83,7 @@ void main() { ...@@ -82,6 +83,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: Scaffold( home: Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
key: scaffoldKey, key: scaffoldKey,
drawer: Drawer( drawer: Drawer(
child: ListView( child: ListView(
...@@ -134,6 +136,7 @@ void main() { ...@@ -134,6 +136,7 @@ void main() {
home: Directionality( home: Directionality(
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Scaffold( child: Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
key: scaffoldKey, key: scaffoldKey,
drawer: Drawer( drawer: Drawer(
child: ListView( child: ListView(
......
...@@ -64,6 +64,7 @@ void main() { ...@@ -64,6 +64,7 @@ void main() {
const Offset upLocation = Offset(10.0, 50.0); // must be far enough to be more than kTouchSlop const Offset upLocation = Offset(10.0, 50.0); // must be far enough to be more than kTouchSlop
final Widget widget = GestureDetector( final Widget widget = GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onVerticalDragUpdate: (DragUpdateDetails details) { dragDistance += details.primaryDelta; }, onVerticalDragUpdate: (DragUpdateDetails details) { dragDistance += details.primaryDelta; },
onVerticalDragEnd: (DragEndDetails details) { gestureCount += 1; }, onVerticalDragEnd: (DragEndDetails details) { gestureCount += 1; },
onHorizontalDragUpdate: (DragUpdateDetails details) { fail('gesture should not match'); }, onHorizontalDragUpdate: (DragUpdateDetails details) { fail('gesture should not match'); },
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import 'states.dart'; import 'states.dart';
...@@ -14,6 +15,7 @@ void main() { ...@@ -14,6 +15,7 @@ void main() {
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: GridView.count( child: GridView.count(
dragStartBehavior: DragStartBehavior.down,
crossAxisCount: 4, crossAxisCount: 4,
children: const <Widget>[], children: const <Widget>[],
), ),
...@@ -28,9 +30,11 @@ void main() { ...@@ -28,9 +30,11 @@ void main() {
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: GridView.count( child: GridView.count(
dragStartBehavior: DragStartBehavior.down,
crossAxisCount: 4, crossAxisCount: 4,
children: kStates.map<Widget>((String state) { children: kStates.map<Widget>((String state) {
return GestureDetector( return GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
log.add(state); log.add(state);
}, },
...@@ -99,9 +103,11 @@ void main() { ...@@ -99,9 +103,11 @@ void main() {
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: GridView.extent( child: GridView.extent(
dragStartBehavior: DragStartBehavior.down,
maxCrossAxisExtent: 200.0, maxCrossAxisExtent: 200.0,
children: kStates.map<Widget>((String state) { children: kStates.map<Widget>((String state) {
return GestureDetector( return GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
log.add(state); log.add(state);
}, },
......
...@@ -1373,8 +1373,11 @@ void main() { ...@@ -1373,8 +1373,11 @@ void main() {
expect(find.byKey(secondKey), isOnstage); expect(find.byKey(secondKey), isOnstage);
expect(find.byKey(secondKey), isInCard); expect(find.byKey(secondKey), isInCard);
final TestGesture gesture = await tester.startGesture(const Offset(5.0, 200.0)); final TestGesture gesture = await tester.startGesture(const Offset(5.0, 200.0));
await gesture.moveBy(const Offset(200.0, 0.0)); await gesture.moveBy(const Offset(20.0, 0.0));
await gesture.moveBy(const Offset(180.0, 0.0));
await gesture.up();
await tester.pump();
await tester.pump(); await tester.pump();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
void main() { void main() {
testWidgets('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async { testWidgets('ListView.builder() fixed itemExtent, scroll to end, append, scroll', (WidgetTester tester) async {
...@@ -13,6 +14,7 @@ void main() { ...@@ -13,6 +14,7 @@ void main() {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
dragStartBehavior: DragStartBehavior.down,
itemExtent: 200.0, itemExtent: 200.0,
itemCount: itemCount, itemCount: itemCount,
itemBuilder: (BuildContext context, int index) => Text('item $index'), itemBuilder: (BuildContext context, int index) => Text('item $index'),
...@@ -40,6 +42,7 @@ void main() { ...@@ -40,6 +42,7 @@ void main() {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
dragStartBehavior: DragStartBehavior.down,
itemCount: itemCount, itemCount: itemCount,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return SizedBox( return SizedBox(
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
...@@ -34,9 +35,11 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) { ...@@ -34,9 +35,11 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) {
child: MediaQuery( child: MediaQuery(
data: const MediaQueryData(), data: const MediaQueryData(),
child: Scaffold( child: Scaffold(
drawerDragStartBehavior: DragStartBehavior.down,
body: DefaultTabController( body: DefaultTabController(
length: 4, length: 4,
child: NestedScrollView( child: NestedScrollView(
dragStartBehavior: DragStartBehavior.down,
controller: controller, controller: controller,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[ return <Widget>[
...@@ -79,6 +82,7 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) { ...@@ -79,6 +82,7 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) {
], ],
), ),
ListView( ListView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
Container( Container(
height: 100.0, height: 100.0,
...@@ -90,6 +94,7 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) { ...@@ -90,6 +94,7 @@ Widget buildTest({ ScrollController controller, String title ='TTTTTTTT' }) {
child: const Center(child: Text('ccc1')), child: const Center(child: Text('ccc1')),
), ),
ListView( ListView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
Container( Container(
height: 10000.0, height: 10000.0,
...@@ -361,6 +366,7 @@ void main() { ...@@ -361,6 +366,7 @@ void main() {
DefaultTabController( DefaultTabController(
length: _tabs.length, // This is the number of tabs. length: _tabs.length, // This is the number of tabs.
child: NestedScrollView( child: NestedScrollView(
dragStartBehavior: DragStartBehavior.down,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
buildCount += 1; // THIS LINE IS NOT IN THE ORIGINAL -- ADDED FOR TEST buildCount += 1; // THIS LINE IS NOT IN THE ORIGINAL -- ADDED FOR TEST
// These are the slivers that show up in the "outer" scroll view. // These are the slivers that show up in the "outer" scroll view.
...@@ -390,12 +396,14 @@ void main() { ...@@ -390,12 +396,14 @@ void main() {
bottom: TabBar( bottom: TabBar(
// These are the widgets to put in each tab in the tab bar. // These are the widgets to put in each tab in the tab bar.
tabs: _tabs.map<Widget>((String name) => Tab(text: name)).toList(), tabs: _tabs.map<Widget>((String name) => Tab(text: name)).toList(),
dragStartBehavior: DragStartBehavior.down,
), ),
), ),
), ),
]; ];
}, },
body: TabBarView( body: TabBarView(
dragStartBehavior: DragStartBehavior.down,
// These are the contents of the tab views, below the tabs. // These are the contents of the tab views, below the tabs.
children: _tabs.map<Widget>((String name) { children: _tabs.map<Widget>((String name) {
return SafeArea( return SafeArea(
...@@ -416,6 +424,7 @@ void main() { ...@@ -416,6 +424,7 @@ void main() {
// it allows the list to remember its scroll position when // it allows the list to remember its scroll position when
// the tab view is not on the screen. // the tab view is not on the screen.
key: PageStorageKey<String>(name), key: PageStorageKey<String>(name),
dragStartBehavior: DragStartBehavior.down,
slivers: <Widget>[ slivers: <Widget>[
SliverOverlapInjector( SliverOverlapInjector(
// This is the flip side of the SliverOverlapAbsorber above. // This is the flip side of the SliverOverlapAbsorber above.
...@@ -590,6 +599,7 @@ void main() { ...@@ -590,6 +599,7 @@ void main() {
child: DefaultTabController( child: DefaultTabController(
length: 1, length: 1,
child: NestedScrollView( child: NestedScrollView(
dragStartBehavior: DragStartBehavior.down,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) { headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[ return <Widget>[
const SliverPersistentHeader( const SliverPersistentHeader(
...@@ -598,6 +608,7 @@ void main() { ...@@ -598,6 +608,7 @@ void main() {
]; ];
}, },
body: SingleChildScrollView( body: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
child: Container( child: Container(
height: 1000.0, height: 1000.0,
child: const Placeholder(key: key2), child: const Placeholder(key: key2),
......
...@@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -6,6 +6,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'semantics_tester.dart'; import 'semantics_tester.dart';
import 'states.dart'; import 'states.dart';
...@@ -19,8 +20,10 @@ void main() { ...@@ -19,8 +20,10 @@ void main() {
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: PageView( child: PageView(
dragStartBehavior: DragStartBehavior.down,
children: kStates.map<Widget>((String state) { children: kStates.map<Widget>((String state) {
return GestureDetector( return GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
log.add(state); log.add(state);
}, },
......
...@@ -60,6 +60,7 @@ void main() { ...@@ -60,6 +60,7 @@ void main() {
return false; return false;
}, },
child: SingleChildScrollView( child: SingleChildScrollView(
dragStartBehavior: DragStartBehavior.down,
child: SizedBox( child: SizedBox(
height: 1200.0, height: 1200.0,
child: NotificationListener<ScrollNotification>( child: NotificationListener<ScrollNotification>(
...@@ -70,11 +71,14 @@ void main() { ...@@ -70,11 +71,14 @@ void main() {
}, },
child: Container( child: Container(
padding: const EdgeInsets.all(50.0), padding: const EdgeInsets.all(50.0),
child: const SingleChildScrollView(child: SizedBox(height: 1200.0)) child: const SingleChildScrollView(
) child: SizedBox(height: 1200.0),
) dragStartBehavior: DragStartBehavior.down,
) ),
) ),
),
),
),
)); ));
final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0)); final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'states.dart'; import 'states.dart';
...@@ -16,6 +17,7 @@ void main() { ...@@ -16,6 +17,7 @@ void main() {
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
children: kStates.map<Widget>((String state) { children: kStates.map<Widget>((String state) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
...@@ -26,6 +28,7 @@ void main() { ...@@ -26,6 +28,7 @@ void main() {
color: const Color(0xFF0000FF), color: const Color(0xFF0000FF),
child: Text(state), child: Text(state),
), ),
dragStartBehavior: DragStartBehavior.down,
); );
}).toList(), }).toList(),
), ),
...@@ -54,6 +57,7 @@ void main() { ...@@ -54,6 +57,7 @@ void main() {
return Directionality( return Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
children: kStates.take(n).map<Widget>((String state) { children: kStates.take(n).map<Widget>((String state) {
return Container( return Container(
height: 200.0, height: 200.0,
...@@ -85,11 +89,13 @@ void main() { ...@@ -85,11 +89,13 @@ void main() {
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: CustomScrollView( child: CustomScrollView(
dragStartBehavior: DragStartBehavior.down,
slivers: <Widget>[ slivers: <Widget>[
SliverList( SliverList(
delegate: SliverChildListDelegate( delegate: SliverChildListDelegate(
kStates.map<Widget>((String state) { kStates.map<Widget>((String state) {
return GestureDetector( return GestureDetector(
dragStartBehavior: DragStartBehavior.down,
onTap: () { onTap: () {
log.add(state); log.add(state);
}, },
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
const TextStyle testFont = TextStyle( const TextStyle testFont = TextStyle(
color: Color(0xFF00FF00), color: Color(0xFF00FF00),
...@@ -19,6 +20,7 @@ Future<void> pumpTest(WidgetTester tester, TargetPlatform platform) async { ...@@ -19,6 +20,7 @@ Future<void> pumpTest(WidgetTester tester, TargetPlatform platform) async {
home: Container( home: Container(
color: const Color(0xFF111111), color: const Color(0xFF111111),
child: ListView.builder( child: ListView.builder(
dragStartBehavior: DragStartBehavior.down,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return Text('$index', style: testFont); return Text('$index', style: testFont);
}, },
...@@ -64,7 +66,7 @@ void main() { ...@@ -64,7 +66,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView(children: textWidgets) child: ListView(children: textWidgets, dragStartBehavior: DragStartBehavior.down)
), ),
); );
...@@ -92,7 +94,7 @@ void main() { ...@@ -92,7 +94,7 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView(children: textWidgets) child: ListView(children: textWidgets, dragStartBehavior: DragStartBehavior.down)
), ),
); );
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
const List<int> items = <int>[0, 1, 2, 3, 4, 5]; const List<int> items = <int>[0, 1, 2, 3, 4, 5];
...@@ -18,6 +19,7 @@ void main() { ...@@ -18,6 +19,7 @@ void main() {
child: Container( child: Container(
height: 50.0, height: 50.0,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
itemExtent: 290.0, itemExtent: 290.0,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: items.map<Widget>((int item) { children: items.map<Widget>((int item) {
...@@ -25,6 +27,7 @@ void main() { ...@@ -25,6 +27,7 @@ void main() {
child: GestureDetector( child: GestureDetector(
onTap: () { tapped.add(item); }, onTap: () { tapped.add(item); },
child: Text('$item'), child: Text('$item'),
dragStartBehavior: DragStartBehavior.down,
), ),
); );
}).toList(), }).toList(),
...@@ -60,6 +63,7 @@ void main() { ...@@ -60,6 +63,7 @@ void main() {
child: Container( child: Container(
width: 50.0, width: 50.0,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
itemExtent: 290.0, itemExtent: 290.0,
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
children: items.map<Widget>((int item) { children: items.map<Widget>((int item) {
...@@ -67,6 +71,7 @@ void main() { ...@@ -67,6 +71,7 @@ void main() {
child: GestureDetector( child: GestureDetector(
onTap: () { tapped.add(item); }, onTap: () { tapped.add(item); },
child: Text('$item'), child: Text('$item'),
dragStartBehavior: DragStartBehavior.down,
), ),
); );
}).toList(), }).toList(),
......
...@@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; ...@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'semantics_tester.dart'; import 'semantics_tester.dart';
...@@ -266,6 +267,7 @@ void main() { ...@@ -266,6 +267,7 @@ void main() {
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: ListView.builder( child: ListView.builder(
dragStartBehavior: DragStartBehavior.down,
itemExtent: 20.0, itemExtent: 20.0,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return Text('entry $index'); return Text('entry $index');
......
...@@ -12,6 +12,7 @@ import 'package:flutter/material.dart'; ...@@ -12,6 +12,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/gestures.dart' show DragStartBehavior;
// Start of block of code where widget creation location line numbers and // Start of block of code where widget creation location line numbers and
// columns will impact whether tests pass. // columns will impact whether tests pass.
...@@ -396,6 +397,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -396,6 +397,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
key: inspectorKey, key: inspectorKey,
selectButtonBuilder: selectButtonBuilder, selectButtonBuilder: selectButtonBuilder,
child: ListView( child: ListView(
dragStartBehavior: DragStartBehavior.down,
children: <Widget>[ children: <Widget>[
Container( Container(
key: childKey, key: childKey,
...@@ -1509,7 +1511,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -1509,7 +1511,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
_CreationLocation location = knownLocations[id]; _CreationLocation location = knownLocations[id];
expect(location.file, equals(file)); expect(location.file, equals(file));
// ClockText widget. // ClockText widget.
expect(location.line, equals(49)); expect(location.line, equals(50));
expect(location.column, equals(9)); expect(location.column, equals(9));
expect(count, equals(1)); expect(count, equals(1));
...@@ -1518,7 +1520,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -1518,7 +1520,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
location = knownLocations[id]; location = knownLocations[id];
expect(location.file, equals(file)); expect(location.file, equals(file));
// Text widget in _ClockTextState build method. // Text widget in _ClockTextState build method.
expect(location.line, equals(87)); expect(location.line, equals(88));
expect(location.column, equals(12)); expect(location.column, equals(12));
expect(count, equals(1)); expect(count, equals(1));
...@@ -1543,7 +1545,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -1543,7 +1545,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
location = knownLocations[id]; location = knownLocations[id];
expect(location.file, equals(file)); expect(location.file, equals(file));
// ClockText widget. // ClockText widget.
expect(location.line, equals(49)); expect(location.line, equals(50));
expect(location.column, equals(9)); expect(location.column, equals(9));
expect(count, equals(3)); // 3 clock widget instances rebuilt. expect(count, equals(3)); // 3 clock widget instances rebuilt.
...@@ -1552,7 +1554,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService { ...@@ -1552,7 +1554,7 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
location = knownLocations[id]; location = knownLocations[id];
expect(location.file, equals(file)); expect(location.file, equals(file));
// Text widget in _ClockTextState build method. // Text widget in _ClockTextState build method.
expect(location.line, equals(87)); expect(location.line, equals(88));
expect(location.column, equals(12)); expect(location.column, equals(12));
expect(count, equals(3)); // 3 clock widget instances rebuilt. expect(count, equals(3)); // 3 clock widget instances rebuilt.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment