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.
This commit is contained in:
parent
868ff42821
commit
08538f91f0
@ -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 {
|
|||||||
@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 {
|
|||||||
),
|
),
|
||||||
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 {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
|
dragStartBehavior: DragStartBehavior.down,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_onOtherAccountsTap(context);
|
_onOtherAccountsTap(context);
|
||||||
},
|
},
|
||||||
@ -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';
|
|||||||
|
|
||||||
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> {
|
|||||||
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> {
|
|||||||
@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> {
|
|||||||
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 @@
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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';
|
|||||||
/// * <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 {
|
|||||||
/// [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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
..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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 @@
|
|||||||
// 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();
|
|||||||
/// * [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 {
|
|||||||
///
|
///
|
||||||
/// 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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
/// 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;
|
|||||||
/// 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;
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
/// 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 {
|
|||||||
onChanged(dayToBuild);
|
onChanged(dayToBuild);
|
||||||
},
|
},
|
||||||
child: dayWidget,
|
child: dayWidget,
|
||||||
|
dragStartBehavior: dragStartBehavior,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 {
|
|||||||
/// 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
|
|||||||
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
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
/// 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> {
|
|||||||
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';
|
|||||||
|
|
||||||
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 {
|
|||||||
@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 {
|
|||||||
/// 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
|
|||||||
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
|
|||||||
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;
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
/// [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> {
|
|||||||
),
|
),
|
||||||
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> {
|
|||||||
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';
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// [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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
..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 {
|
|||||||
@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 {
|
|||||||
_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 {
|
|||||||
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;
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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> {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
/// 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> {
|
|||||||
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';
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// {@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
|
|||||||
scrollPadding: widget.scrollPadding,
|
scrollPadding: widget.scrollPadding,
|
||||||
keyboardAppearance: keyboardAppearance,
|
keyboardAppearance: keyboardAppearance,
|
||||||
enableInteractiveSelection: widget.enableInteractiveSelection,
|
enableInteractiveSelection: widget.enableInteractiveSelection,
|
||||||
|
dragStartBehavior: widget.dragStartBehavior,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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 {
|
|||||||
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 {
|
|||||||
/// 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
|
|||||||
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
|
|||||||
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
|
|||||||
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;
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
/// 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
|
|||||||
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
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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 {
|
|||||||
..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 {
|
|||||||
..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 {
|
|||||||
..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 {
|
|||||||
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 {
|
|||||||
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';
|
|||||||
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
|
|||||||
/// 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 {
|
|||||||
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 {
|
|||||||
/// 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> {
|
|||||||
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 {
|
|||||||
@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;
|
|||||||
|
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// 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> {
|
|||||||
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 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// * [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 {
|
|||||||
? 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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
/// * [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
|
|||||||
..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
|
|||||||
..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 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
/// {@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 {
|
|||||||
? 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;
|
|||||||
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 {
|
|||||||
@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 {
|
|||||||
/// 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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
selection: _selection,
|
selection: _selection,
|
||||||
selectionControls: selectionControls,
|
selectionControls: selectionControls,
|
||||||
position: position,
|
position: position,
|
||||||
|
dragStartBehavior: dragStartBehavior,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -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 {
|
|||||||
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
|
|||||||
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 @@
|
|||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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;
|
||||||
|
@ -58,8 +58,7 @@ void main() {
|
|||||||
tester.route(pointer.move(const Offset(20.0, 30.0))); // moved 10 horizontally and 20 vertically which is 22 total
|
tester.route(pointer.move(const Offset(20.0, 30.0))); // moved 10 horizontally and 20 vertically which is 22 total
|
||||||
expect(didStartPan, isTrue); // 22 > 18
|
expect(didStartPan, isTrue); // 22 > 18
|
||||||
didStartPan = false;
|
didStartPan = false;
|
||||||
expect(updatedScrollDelta, const Offset(10.0, 20.0));
|
expect(updatedScrollDelta, null);
|
||||||
updatedScrollDelta = null;
|
|
||||||
expect(didEndPan, isFalse);
|
expect(didEndPan, isFalse);
|
||||||
expect(didTap, isFalse);
|
expect(didTap, isFalse);
|
||||||
|
|
||||||
@ -82,7 +81,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Should recognize drag', (GestureTester tester) {
|
testGesture('Should recognize drag', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
bool didStartDrag = false;
|
bool didStartDrag = false;
|
||||||
drag.onStart = (_) {
|
drag.onStart = (_) {
|
||||||
@ -135,7 +134,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Should report original timestamps', (GestureTester tester) {
|
testGesture('Should report original timestamps', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
Duration startTimestamp;
|
Duration startTimestamp;
|
||||||
drag.onStart = (DragStartDetails details) {
|
drag.onStart = (DragStartDetails details) {
|
||||||
@ -165,9 +164,98 @@ void main() {
|
|||||||
drag.dispose();
|
drag.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Drag with multiple pointers', (GestureTester tester) {
|
testGesture('Should report most recent point to onStart by default', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag1 = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
||||||
final VerticalDragGestureRecognizer drag2 = VerticalDragGestureRecognizer();
|
final VerticalDragGestureRecognizer competingDrag = VerticalDragGestureRecognizer();
|
||||||
|
|
||||||
|
Offset positionAtOnStart;
|
||||||
|
drag.onStart = (DragStartDetails details) {
|
||||||
|
positionAtOnStart = details.globalPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
final TestPointer pointer = TestPointer(5);
|
||||||
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
||||||
|
drag.addPointer(down);
|
||||||
|
competingDrag.addPointer(down);
|
||||||
|
tester.closeArena(5);
|
||||||
|
tester.route(down);
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(30.0, 0.0)));
|
||||||
|
drag.dispose();
|
||||||
|
competingDrag.dispose();
|
||||||
|
|
||||||
|
expect(positionAtOnStart, const Offset(30.0, 00.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
testGesture('Should report most recent point to onStart with a start configuration', (GestureTester tester) {
|
||||||
|
final HorizontalDragGestureRecognizer drag =
|
||||||
|
HorizontalDragGestureRecognizer();
|
||||||
|
final VerticalDragGestureRecognizer competingDrag = VerticalDragGestureRecognizer();
|
||||||
|
|
||||||
|
Offset positionAtOnStart;
|
||||||
|
drag.onStart = (DragStartDetails details) {
|
||||||
|
positionAtOnStart = details.globalPosition;
|
||||||
|
};
|
||||||
|
Offset updateOffset;
|
||||||
|
drag.onUpdate = (DragUpdateDetails details) {
|
||||||
|
updateOffset = details.globalPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
final TestPointer pointer = TestPointer(5);
|
||||||
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
||||||
|
drag.addPointer(down);
|
||||||
|
competingDrag.addPointer(down);
|
||||||
|
tester.closeArena(5);
|
||||||
|
tester.route(down);
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(30.0, 0.0)));
|
||||||
|
drag.dispose();
|
||||||
|
competingDrag.dispose();
|
||||||
|
|
||||||
|
expect(positionAtOnStart, const Offset(30.0, 0.0));
|
||||||
|
expect(updateOffset, null);
|
||||||
|
});
|
||||||
|
|
||||||
|
testGesture('Should report initial down point to onStart with a down configuration', (GestureTester tester) {
|
||||||
|
final HorizontalDragGestureRecognizer drag =
|
||||||
|
HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
final VerticalDragGestureRecognizer competingDrag = VerticalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
|
Offset positionAtOnStart;
|
||||||
|
drag.onStart = (DragStartDetails details) {
|
||||||
|
positionAtOnStart = details.globalPosition;
|
||||||
|
};
|
||||||
|
Offset updateOffset;
|
||||||
|
Offset updateDelta;
|
||||||
|
drag.onUpdate = (DragUpdateDetails details) {
|
||||||
|
updateOffset = details.globalPosition;
|
||||||
|
updateDelta = details.delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
final TestPointer pointer = TestPointer(5);
|
||||||
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
||||||
|
drag.addPointer(down);
|
||||||
|
competingDrag.addPointer(down);
|
||||||
|
tester.closeArena(5);
|
||||||
|
tester.route(down);
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(30.0, 0.0)));
|
||||||
|
drag.dispose();
|
||||||
|
competingDrag.dispose();
|
||||||
|
|
||||||
|
expect(positionAtOnStart, const Offset(10.0, 10.0));
|
||||||
|
|
||||||
|
// The drag is horizontal so we're going to ignore the vertical delta position
|
||||||
|
// when calculating the new global position.
|
||||||
|
expect(updateOffset, const Offset(30.0, 10.0));
|
||||||
|
expect(updateDelta, const Offset(20.0, 0.0));
|
||||||
|
});
|
||||||
|
|
||||||
|
testGesture('Drag with multiple pointers in down behavior', (GestureTester tester) {
|
||||||
|
final HorizontalDragGestureRecognizer drag1 =
|
||||||
|
HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
final VerticalDragGestureRecognizer drag2 =
|
||||||
|
VerticalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
final List<String> log = <String>[];
|
final List<String> log = <String>[];
|
||||||
drag1.onDown = (_) { log.add('drag1-down'); };
|
drag1.onDown = (_) { log.add('drag1-down'); };
|
||||||
@ -235,7 +323,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Clamp max velocity', (GestureTester tester) {
|
testGesture('Clamp max velocity', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
Velocity velocity;
|
Velocity velocity;
|
||||||
double primaryVelocity;
|
double primaryVelocity;
|
||||||
@ -269,7 +357,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Synthesized pointer events are ignored for velocity tracking', (GestureTester tester) {
|
testGesture('Synthesized pointer events are ignored for velocity tracking', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
Velocity velocity;
|
Velocity velocity;
|
||||||
drag.onEnd = (DragEndDetails details) {
|
drag.onEnd = (DragEndDetails details) {
|
||||||
@ -303,7 +391,7 @@ void main() {
|
|||||||
/// Checks that quick flick gestures with 1 down, 2 move and 1 up pointer
|
/// Checks that quick flick gestures with 1 down, 2 move and 1 up pointer
|
||||||
/// events still have a velocity
|
/// events still have a velocity
|
||||||
testGesture('Quick flicks have velocity', (GestureTester tester) {
|
testGesture('Quick flicks have velocity', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
Velocity velocity;
|
Velocity velocity;
|
||||||
drag.onEnd = (DragEndDetails details) {
|
drag.onEnd = (DragEndDetails details) {
|
||||||
@ -333,16 +421,18 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Should recognize drag', (GestureTester tester) {
|
testGesture('Should recognize drag', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
bool didStartDrag = false;
|
bool didStartDrag = false;
|
||||||
drag.onStart = (_) {
|
drag.onStart = (_) {
|
||||||
didStartDrag = true;
|
didStartDrag = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
double updatedDelta;
|
Offset updateDelta;
|
||||||
|
double updatePrimaryDelta;
|
||||||
drag.onUpdate = (DragUpdateDetails details) {
|
drag.onUpdate = (DragUpdateDetails details) {
|
||||||
updatedDelta = details.primaryDelta;
|
updateDelta = details.delta;
|
||||||
|
updatePrimaryDelta = details.primaryDelta;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool didEndDrag = false;
|
bool didEndDrag = false;
|
||||||
@ -354,31 +444,39 @@ void main() {
|
|||||||
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
||||||
drag.addPointer(down);
|
drag.addPointer(down);
|
||||||
tester.closeArena(5);
|
tester.closeArena(5);
|
||||||
|
|
||||||
expect(didStartDrag, isFalse);
|
expect(didStartDrag, isFalse);
|
||||||
expect(updatedDelta, isNull);
|
expect(updateDelta, isNull);
|
||||||
|
expect(updatePrimaryDelta, isNull);
|
||||||
expect(didEndDrag, isFalse);
|
expect(didEndDrag, isFalse);
|
||||||
|
|
||||||
tester.route(down);
|
tester.route(down);
|
||||||
expect(didStartDrag, isTrue);
|
expect(didStartDrag, isTrue);
|
||||||
expect(updatedDelta, isNull);
|
expect(updateDelta, isNull);
|
||||||
|
expect(updatePrimaryDelta, isNull);
|
||||||
expect(didEndDrag, isFalse);
|
expect(didEndDrag, isFalse);
|
||||||
|
|
||||||
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
|
||||||
expect(didStartDrag, isTrue);
|
|
||||||
didStartDrag = false;
|
didStartDrag = false;
|
||||||
expect(updatedDelta, 10.0);
|
|
||||||
updatedDelta = null;
|
|
||||||
expect(didEndDrag, isFalse);
|
|
||||||
|
|
||||||
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
||||||
expect(didStartDrag, isFalse);
|
expect(didStartDrag, isFalse);
|
||||||
expect(updatedDelta, 0.0);
|
expect(updateDelta, const Offset(10.0, 0.0));
|
||||||
updatedDelta = null;
|
expect(updatePrimaryDelta, 10.0);
|
||||||
expect(didEndDrag, isFalse);
|
expect(didEndDrag, isFalse);
|
||||||
|
updateDelta = null;
|
||||||
|
updatePrimaryDelta = null;
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
||||||
|
expect(didStartDrag, isFalse);
|
||||||
|
expect(updateDelta, const Offset(0.0, 0.0));
|
||||||
|
expect(updatePrimaryDelta, 0.0);
|
||||||
|
expect(didEndDrag, isFalse);
|
||||||
|
updateDelta = null;
|
||||||
|
updatePrimaryDelta = null;
|
||||||
|
|
||||||
tester.route(pointer.up());
|
tester.route(pointer.up());
|
||||||
expect(didStartDrag, isFalse);
|
expect(didStartDrag, isFalse);
|
||||||
expect(updatedDelta, isNull);
|
expect(updateDelta, isNull);
|
||||||
|
expect(updatePrimaryDelta, isNull);
|
||||||
expect(didEndDrag, isTrue);
|
expect(didEndDrag, isTrue);
|
||||||
didEndDrag = false;
|
didEndDrag = false;
|
||||||
|
|
||||||
@ -386,21 +484,36 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
testGesture('Should recognize drag', (GestureTester tester) {
|
testGesture('Should recognize drag', (GestureTester tester) {
|
||||||
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
|
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer() ..dragStartBehavior = DragStartBehavior.down;
|
||||||
|
|
||||||
Offset newGlobalPosition;
|
Offset latestGlobalPosition;
|
||||||
|
drag.onStart = (DragStartDetails details) {
|
||||||
|
latestGlobalPosition = details.globalPosition;
|
||||||
|
};
|
||||||
|
Offset latestDelta;
|
||||||
drag.onUpdate = (DragUpdateDetails details) {
|
drag.onUpdate = (DragUpdateDetails details) {
|
||||||
newGlobalPosition = details.globalPosition;
|
latestGlobalPosition = details.globalPosition;
|
||||||
|
latestDelta = details.delta;
|
||||||
};
|
};
|
||||||
|
|
||||||
final TestPointer pointer = TestPointer(5);
|
final TestPointer pointer = TestPointer(5);
|
||||||
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
final PointerDownEvent down = pointer.down(const Offset(10.0, 10.0));
|
||||||
drag.addPointer(down);
|
drag.addPointer(down);
|
||||||
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
|
||||||
tester.closeArena(5);
|
tester.closeArena(5);
|
||||||
|
|
||||||
tester.route(down);
|
tester.route(down);
|
||||||
expect(newGlobalPosition, const Offset(20.0, 10.0));
|
expect(latestGlobalPosition, const Offset(10.0, 10.0));
|
||||||
|
expect(latestDelta, isNull);
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(20.0, 25.0)));
|
||||||
|
expect(latestGlobalPosition, const Offset(20.0, 25.0));
|
||||||
|
expect(latestDelta, const Offset(10.0, 0.0));
|
||||||
|
|
||||||
|
tester.route(pointer.move(const Offset(0.0, 45.0)));
|
||||||
|
expect(latestGlobalPosition, const Offset(0.0, 45.0));
|
||||||
|
expect(latestDelta, const Offset(-20.0, 0.0));
|
||||||
|
|
||||||
tester.route(pointer.up());
|
tester.route(pointer.up());
|
||||||
drag.dispose();
|
drag.dispose();
|
||||||
});
|
});
|
||||||
}
|
}
|
@ -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() {
|
|||||||
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() {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(_selectedDate, equals(DateTime(2016, DateTime.july, 26)));
|
expect(_selectedDate, equals(DateTime(2016, DateTime.july, 26)));
|
||||||
|
@ -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() {
|
|||||||
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 @@
|
|||||||
|
|
||||||
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() {
|
|||||||
|
|
||||||
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';
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
// 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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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';
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
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
|
|||||||
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
|
|||||||
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 {
|
|||||||
@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() {
|
|||||||
|
|
||||||
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() {
|
|||||||
|
|
||||||
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';
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
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' }) {
|
|||||||
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' }) {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
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' }) {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
// 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() {
|
|||||||
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() {
|
|||||||
];
|
];
|
||||||
},
|
},
|
||||||
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';
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
},
|
},
|
||||||
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 @@
|
|||||||
|
|
||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
|
|
||||||
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 {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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 @@
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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() {
|
|||||||
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';
|
|||||||
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() {
|
|||||||
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';
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
_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 {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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.
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user