Just-in-time mutations of GestureDetector
This allows us to adjust exactly which gestures we're listening for during layout, which I'll use to kill a SizeObserver.
This commit is contained in:
parent
d1154c2573
commit
0df3730d3e
@ -6,6 +6,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.MaterialGallery" android:versionCode="1" android:versionName="0.0.1">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.flutter.MaterialGallery" android:versionCode="1" android:versionName="0.0.1">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
<application android:icon="@mipmap/ic_launcher" android:label="Flutter Material" android:name="org.domokit.sky.shell.SkyApplication">
|
<application android:icon="@mipmap/ic_launcher" android:label="Flutter Material" android:name="org.domokit.sky.shell.SkyApplication">
|
||||||
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize" android:hardwareAccelerated="true" android:launchMode="singleTask" android:name="org.domokit.sky.shell.SkyActivity" android:theme="@android:style/Theme.Black.NoTitleBar">
|
||||||
|
@ -143,6 +143,8 @@ class VerticalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
|||||||
double get _initialPendingDragDelta => 0.0;
|
double get _initialPendingDragDelta => 0.0;
|
||||||
double _getDragDelta(PointerEvent event) => event.delta.dy;
|
double _getDragDelta(PointerEvent event) => event.delta.dy;
|
||||||
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
|
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
|
||||||
|
|
||||||
|
String toStringShort() => 'vertical drag';
|
||||||
}
|
}
|
||||||
|
|
||||||
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
||||||
@ -163,6 +165,8 @@ class HorizontalDragGestureRecognizer extends _DragGestureRecognizer<double> {
|
|||||||
double get _initialPendingDragDelta => 0.0;
|
double get _initialPendingDragDelta => 0.0;
|
||||||
double _getDragDelta(PointerEvent event) => event.delta.dx;
|
double _getDragDelta(PointerEvent event) => event.delta.dx;
|
||||||
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
|
bool get _hasSufficientPendingDragDeltaToAccept => _pendingDragDelta.abs() > kTouchSlop;
|
||||||
|
|
||||||
|
String toStringShort() => 'horizontal drag';
|
||||||
}
|
}
|
||||||
|
|
||||||
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
|
class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
|
||||||
@ -185,4 +189,6 @@ class PanGestureRecognizer extends _DragGestureRecognizer<Offset> {
|
|||||||
bool get _hasSufficientPendingDragDeltaToAccept {
|
bool get _hasSufficientPendingDragDeltaToAccept {
|
||||||
return _pendingDragDelta.distance > kPanSlop;
|
return _pendingDragDelta.distance > kPanSlop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'pan';
|
||||||
}
|
}
|
||||||
|
@ -34,4 +34,6 @@ class LongPressGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
|||||||
if (event is PointerUpEvent)
|
if (event is PointerUpEvent)
|
||||||
resolve(GestureDisposition.rejected);
|
resolve(GestureDisposition.rejected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'long press';
|
||||||
}
|
}
|
||||||
|
@ -250,6 +250,8 @@ class ImmediateMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_Im
|
|||||||
_ImmediatePointerState createNewPointerState(PointerDownEvent event) {
|
_ImmediatePointerState createNewPointerState(PointerDownEvent event) {
|
||||||
return new _ImmediatePointerState(event.position);
|
return new _ImmediatePointerState(event.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'multidrag';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -277,6 +279,8 @@ class HorizontalMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_H
|
|||||||
_HorizontalPointerState createNewPointerState(PointerDownEvent event) {
|
_HorizontalPointerState createNewPointerState(PointerDownEvent event) {
|
||||||
return new _HorizontalPointerState(event.position);
|
return new _HorizontalPointerState(event.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'horizontal multidrag';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -304,6 +308,8 @@ class VerticalMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_Ver
|
|||||||
_VerticalPointerState createNewPointerState(PointerDownEvent event) {
|
_VerticalPointerState createNewPointerState(PointerDownEvent event) {
|
||||||
return new _VerticalPointerState(event.position);
|
return new _VerticalPointerState(event.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'vertical multidrag';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -373,4 +379,6 @@ class DelayedMultiDragGestureRecognizer extends MultiDragGestureRecognizer<_Dela
|
|||||||
_DelayedPointerState createNewPointerState(PointerDownEvent event) {
|
_DelayedPointerState createNewPointerState(PointerDownEvent event) {
|
||||||
return new _DelayedPointerState(event.position, _delay);
|
return new _DelayedPointerState(event.position, _delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'long multidrag';
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,7 @@ class DoubleTapGestureRecognizer extends GestureRecognizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'double tap';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -385,4 +386,5 @@ class MultiTapGestureRecognizer extends GestureRecognizer {
|
|||||||
_gestureArena = null;
|
_gestureArena = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'multitap';
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,9 @@ abstract class GestureRecognizer extends GestureArenaMember {
|
|||||||
/// GestureDetector widget calls this method).
|
/// GestureDetector widget calls this method).
|
||||||
void dispose() { }
|
void dispose() { }
|
||||||
|
|
||||||
|
/// Returns a very short pretty description of the gesture that the
|
||||||
|
/// recognizer looks for, like 'tap' or 'horizontal drag'.
|
||||||
|
String toStringShort() => toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Base class for gesture recognizers that can only recognize one
|
/// Base class for gesture recognizers that can only recognize one
|
||||||
|
@ -135,4 +135,6 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
|
|||||||
}
|
}
|
||||||
_state = ScaleState.ready;
|
_state = ScaleState.ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'scale';
|
||||||
}
|
}
|
||||||
|
@ -102,4 +102,6 @@ class TapGestureRecognizer extends PrimaryPointerGestureRecognizer {
|
|||||||
_wonArena = false;
|
_wonArena = false;
|
||||||
_finalPosition = null;
|
_finalPosition = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String toStringShort() => 'tap';
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ export 'package:flutter/gestures.dart' show
|
|||||||
GestureScaleEndCallback,
|
GestureScaleEndCallback,
|
||||||
Velocity;
|
Velocity;
|
||||||
|
|
||||||
|
typedef GestureRecognizer GestureRecognizerFactory(GestureRecognizer recognizer, PointerRouter router, GestureArena arena);
|
||||||
|
|
||||||
/// A widget that detects gestures.
|
/// A widget that detects gestures.
|
||||||
///
|
///
|
||||||
/// Attempts to recognize gestures that correspond to its non-null callbacks.
|
/// Attempts to recognize gestures that correspond to its non-null callbacks.
|
||||||
@ -37,8 +39,8 @@ export 'package:flutter/gestures.dart' show
|
|||||||
/// [excludeFromSemantics] to true.
|
/// [excludeFromSemantics] to true.
|
||||||
///
|
///
|
||||||
/// See http://flutter.io/gestures/ for additional information.
|
/// See http://flutter.io/gestures/ for additional information.
|
||||||
class GestureDetector extends StatefulComponent {
|
class GestureDetector extends StatelessComponent {
|
||||||
const GestureDetector({
|
GestureDetector({
|
||||||
Key key,
|
Key key,
|
||||||
this.child,
|
this.child,
|
||||||
this.onTapDown,
|
this.onTapDown,
|
||||||
@ -61,7 +63,23 @@ class GestureDetector extends StatefulComponent {
|
|||||||
this.onScaleEnd,
|
this.onScaleEnd,
|
||||||
this.behavior,
|
this.behavior,
|
||||||
this.excludeFromSemantics: false
|
this.excludeFromSemantics: false
|
||||||
}) : super(key: key);
|
}) : super(key: key) {
|
||||||
|
assert(excludeFromSemantics != null);
|
||||||
|
assert(() {
|
||||||
|
bool haveVerticalDrag = onVerticalDragStart != null || onVerticalDragUpdate != null || onVerticalDragEnd != null;
|
||||||
|
bool haveHorizontalDrag = onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null;
|
||||||
|
bool havePan = onPanStart != null || onPanUpdate != null || onPanEnd != null;
|
||||||
|
bool haveScale = onScaleStart != null || onScaleUpdate != null || onScaleEnd != null;
|
||||||
|
if (havePan || haveScale) {
|
||||||
|
if (havePan && haveScale)
|
||||||
|
throw new WidgetError('Having both a pan gesture recognizer and a scale gesture recognizer is redundant; scale is a superset of pan. Just use the scale gesture recognizer.');
|
||||||
|
String recognizer = havePan ? 'pan' : 'scale';
|
||||||
|
if (haveVerticalDrag && haveHorizontalDrag)
|
||||||
|
throw new WidgetError('Simultaneously having a vertical drag gesture recognizer, a horizontal drag gesture recognizer, and a $recognizer gesture recognizer will result in the $recognizer gesture recognizer being ignored, since the other two will catch all drags.');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@ -130,151 +148,192 @@ class GestureDetector extends StatefulComponent {
|
|||||||
/// duplication of information.
|
/// duplication of information.
|
||||||
final bool excludeFromSemantics;
|
final bool excludeFromSemantics;
|
||||||
|
|
||||||
_GestureDetectorState createState() => new _GestureDetectorState();
|
Widget build(BuildContext context) {
|
||||||
|
Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
|
||||||
|
|
||||||
|
if (onTapDown != null || onTapUp != null || onTap != null || onTapCancel != null) {
|
||||||
|
gestures[TapGestureRecognizer] = (TapGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new TapGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onTapDown = onTapDown
|
||||||
|
..onTapUp = onTapUp
|
||||||
|
..onTap = onTap
|
||||||
|
..onTapCancel = onTapCancel;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onDoubleTap != null) {
|
||||||
|
gestures[DoubleTapGestureRecognizer] = (DoubleTapGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new DoubleTapGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onDoubleTap = onDoubleTap;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onLongPress != null) {
|
||||||
|
gestures[LongPressGestureRecognizer] = (LongPressGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new LongPressGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onLongPress = onLongPress;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onVerticalDragStart != null || onVerticalDragUpdate != null || onVerticalDragEnd != null) {
|
||||||
|
gestures[VerticalDragGestureRecognizer] = (VerticalDragGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new VerticalDragGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onStart = onVerticalDragStart
|
||||||
|
..onUpdate = onVerticalDragUpdate
|
||||||
|
..onEnd = onVerticalDragEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onHorizontalDragStart != null || onHorizontalDragUpdate != null || onHorizontalDragEnd != null) {
|
||||||
|
gestures[HorizontalDragGestureRecognizer] = (HorizontalDragGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new HorizontalDragGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onStart = onHorizontalDragStart
|
||||||
|
..onUpdate = onHorizontalDragUpdate
|
||||||
|
..onEnd = onHorizontalDragEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onPanStart != null || onPanUpdate != null || onPanEnd != null) {
|
||||||
|
gestures[PanGestureRecognizer] = (PanGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new PanGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onStart = onPanStart
|
||||||
|
..onUpdate = onPanUpdate
|
||||||
|
..onEnd = onPanEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onScaleStart != null || onScaleUpdate != null || onScaleEnd != null) {
|
||||||
|
gestures[ScaleGestureRecognizer] = (ScaleGestureRecognizer recognizer, PointerRouter router, GestureArena arena) {
|
||||||
|
return (recognizer ??= new ScaleGestureRecognizer(router: router, gestureArena: arena))
|
||||||
|
..onStart = onScaleStart
|
||||||
|
..onUpdate = onScaleUpdate
|
||||||
|
..onEnd = onScaleEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RawGestureDetector(
|
||||||
|
gestures: gestures,
|
||||||
|
behavior: behavior,
|
||||||
|
excludeFromSemantics: excludeFromSemantics,
|
||||||
|
child: child
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _GestureDetectorState extends State<GestureDetector> {
|
/// A widget that detects gestures described by the given gesture
|
||||||
PointerRouter get _router => Gesturer.instance.pointerRouter;
|
/// factories.
|
||||||
|
///
|
||||||
|
/// For common gestures, use a [GestureRecognizer].
|
||||||
|
/// RawGestureDetector is useful primarily when developing your
|
||||||
|
/// own gesture recognizers.
|
||||||
|
class RawGestureDetector extends StatefulComponent {
|
||||||
|
RawGestureDetector({
|
||||||
|
Key key,
|
||||||
|
this.child,
|
||||||
|
this.gestures: const <Type, GestureRecognizerFactory>{},
|
||||||
|
this.behavior,
|
||||||
|
this.excludeFromSemantics: false
|
||||||
|
}) : super(key: key) {
|
||||||
|
assert(gestures != null);
|
||||||
|
assert(excludeFromSemantics != null);
|
||||||
|
}
|
||||||
|
|
||||||
TapGestureRecognizer _tap;
|
final Widget child;
|
||||||
DoubleTapGestureRecognizer _doubleTap;
|
|
||||||
LongPressGestureRecognizer _longPress;
|
final Map<Type, GestureRecognizerFactory> gestures;
|
||||||
VerticalDragGestureRecognizer _verticalDrag;
|
|
||||||
HorizontalDragGestureRecognizer _horizontalDrag;
|
/// How this gesture detector should behave during hit testing.
|
||||||
PanGestureRecognizer _pan;
|
final HitTestBehavior behavior;
|
||||||
ScaleGestureRecognizer _scale;
|
|
||||||
|
/// Whether to exclude these gestures from the semantics tree. For
|
||||||
|
/// example, the long-press gesture for showing a tooltip is
|
||||||
|
/// excluded because the tooltip itself is included in the semantics
|
||||||
|
/// tree directly and so having a gesture to show it would result in
|
||||||
|
/// duplication of information.
|
||||||
|
final bool excludeFromSemantics;
|
||||||
|
|
||||||
|
RawGestureDetectorState createState() => new RawGestureDetectorState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class RawGestureDetectorState extends State<RawGestureDetector> {
|
||||||
|
|
||||||
|
Map<Type, GestureRecognizer> _recognizers = const <Type, GestureRecognizer>{};
|
||||||
|
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_syncAll();
|
_syncAll(config.gestures);
|
||||||
}
|
}
|
||||||
|
|
||||||
void didUpdateConfig(GestureDetector oldConfig) {
|
void didUpdateConfig(RawGestureDetector oldConfig) {
|
||||||
_syncAll();
|
_syncAll(config.gestures);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This method can be called after the build phase, during the
|
||||||
|
/// layout of the nearest descendant RenderObjectWidget of the
|
||||||
|
/// gesture detector, to update the list of active gesture
|
||||||
|
/// recognizers.
|
||||||
|
///
|
||||||
|
/// The typical use case is [Scrollable]s, which put their viewport
|
||||||
|
/// in their gesture detector, and then need to know the dimensions
|
||||||
|
/// of the viewport and the viewport's child to determine whether
|
||||||
|
/// the gesture detector should be enabled.
|
||||||
|
void replaceGestureRecognizers(Map<Type, GestureRecognizerFactory> gestures) {
|
||||||
|
assert(() {
|
||||||
|
RenderObject renderObject = context.findRenderObject();
|
||||||
|
assert(renderObject is RenderPointerListener);
|
||||||
|
RenderPointerListener listener = renderObject;
|
||||||
|
RenderBox descendant = listener.child;
|
||||||
|
if (!config.excludeFromSemantics) {
|
||||||
|
assert(descendant is RenderSemanticsGestureHandler);
|
||||||
|
RenderSemanticsGestureHandler semanticsGestureHandler = descendant;
|
||||||
|
descendant = semanticsGestureHandler.child;
|
||||||
|
}
|
||||||
|
assert(descendant != null);
|
||||||
|
if (!descendant.debugDoingThisLayout) {
|
||||||
|
throw new WidgetError(
|
||||||
|
'replaceGestureRecognizers() can only be called during the layout phase of the GestureDetector\'s nearest descendant RenderObjectWidget.\n'
|
||||||
|
'In this particular case, that is:\n'
|
||||||
|
' $descendant'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
_syncAll(gestures);
|
||||||
|
if (!config.excludeFromSemantics) {
|
||||||
|
RenderPointerListener listener = context.findRenderObject();
|
||||||
|
RenderSemanticsGestureHandler semanticsGestureHandler = listener.child;
|
||||||
|
context.visitChildElements((RenderObjectElement element) => element.widget.updateRenderObject(semanticsGestureHandler, null));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_tap = _ensureDisposed(_tap);
|
for (GestureRecognizer recognizer in _recognizers.values)
|
||||||
_doubleTap = _ensureDisposed(_doubleTap);
|
recognizer.dispose();
|
||||||
_longPress = _ensureDisposed(_longPress);
|
_recognizers = null;
|
||||||
_verticalDrag = _ensureDisposed(_verticalDrag);
|
|
||||||
_horizontalDrag = _ensureDisposed(_horizontalDrag);
|
|
||||||
_pan = _ensureDisposed(_pan);
|
|
||||||
_scale = _ensureDisposed(_scale);
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _syncAll() {
|
void _syncAll(Map<Type, GestureRecognizerFactory> gestures) {
|
||||||
_syncTap();
|
final PointerRouter pointerRouter = Gesturer.instance.pointerRouter;
|
||||||
_syncDoubleTap();
|
final GestureArena gestureArena = Gesturer.instance.gestureArena;
|
||||||
_syncLongPress();
|
assert(_recognizers != null);
|
||||||
_syncVerticalDrag();
|
Map<Type, GestureRecognizer> oldRecognizers = _recognizers;
|
||||||
_syncHorizontalDrag();
|
_recognizers = <Type, GestureRecognizer>{};
|
||||||
_syncPan();
|
for (Type type in gestures.keys) {
|
||||||
_syncScale();
|
assert(!_recognizers.containsKey(type));
|
||||||
}
|
_recognizers[type] = gestures[type](oldRecognizers[type], pointerRouter, gestureArena);
|
||||||
|
assert(_recognizers[type].runtimeType == type);
|
||||||
void _syncTap() {
|
|
||||||
if (config.onTapDown == null && config.onTapUp == null && config.onTap == null && config.onTapCancel == null) {
|
|
||||||
_tap = _ensureDisposed(_tap);
|
|
||||||
} else {
|
|
||||||
_tap ??= new TapGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_tap
|
|
||||||
..onTapDown = config.onTapDown
|
|
||||||
..onTapUp = config.onTapUp
|
|
||||||
..onTap = config.onTap
|
|
||||||
..onTapCancel = config.onTapCancel;
|
|
||||||
}
|
}
|
||||||
}
|
for (Type type in oldRecognizers.keys) {
|
||||||
|
if (!_recognizers.containsKey(type))
|
||||||
void _syncDoubleTap() {
|
oldRecognizers[type].dispose();
|
||||||
if (config.onDoubleTap == null) {
|
|
||||||
_doubleTap = _ensureDisposed(_doubleTap);
|
|
||||||
} else {
|
|
||||||
_doubleTap ??= new DoubleTapGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_doubleTap.onDoubleTap = config.onDoubleTap;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _syncLongPress() {
|
|
||||||
if (config.onLongPress == null) {
|
|
||||||
_longPress = _ensureDisposed(_longPress);
|
|
||||||
} else {
|
|
||||||
_longPress ??= new LongPressGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_longPress.onLongPress = config.onLongPress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _syncVerticalDrag() {
|
|
||||||
if (config.onVerticalDragStart == null && config.onVerticalDragUpdate == null && config.onVerticalDragEnd == null) {
|
|
||||||
_verticalDrag = _ensureDisposed(_verticalDrag);
|
|
||||||
} else {
|
|
||||||
_verticalDrag ??= new VerticalDragGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_verticalDrag
|
|
||||||
..onStart = config.onVerticalDragStart
|
|
||||||
..onUpdate = config.onVerticalDragUpdate
|
|
||||||
..onEnd = config.onVerticalDragEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _syncHorizontalDrag() {
|
|
||||||
if (config.onHorizontalDragStart == null && config.onHorizontalDragUpdate == null && config.onHorizontalDragEnd == null) {
|
|
||||||
_horizontalDrag = _ensureDisposed(_horizontalDrag);
|
|
||||||
} else {
|
|
||||||
_horizontalDrag ??= new HorizontalDragGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_horizontalDrag
|
|
||||||
..onStart = config.onHorizontalDragStart
|
|
||||||
..onUpdate = config.onHorizontalDragUpdate
|
|
||||||
..onEnd = config.onHorizontalDragEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _syncPan() {
|
|
||||||
if (config.onPanStart == null && config.onPanUpdate == null && config.onPanEnd == null) {
|
|
||||||
_pan = _ensureDisposed(_pan);
|
|
||||||
} else {
|
|
||||||
assert(_scale == null); // Scale is a superset of pan; just use scale
|
|
||||||
_pan ??= new PanGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_pan
|
|
||||||
..onStart = config.onPanStart
|
|
||||||
..onUpdate = config.onPanUpdate
|
|
||||||
..onEnd = config.onPanEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _syncScale() {
|
|
||||||
if (config.onScaleStart == null && config.onScaleUpdate == null && config.onScaleEnd == null) {
|
|
||||||
_scale = _ensureDisposed(_scale);
|
|
||||||
} else {
|
|
||||||
assert(_pan == null); // Scale is a superset of pan; just use scale
|
|
||||||
_scale ??= new ScaleGestureRecognizer(router: _router, gestureArena: Gesturer.instance.gestureArena);
|
|
||||||
_scale
|
|
||||||
..onStart = config.onScaleStart
|
|
||||||
..onUpdate = config.onScaleUpdate
|
|
||||||
..onEnd = config.onScaleEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GestureRecognizer _ensureDisposed(GestureRecognizer recognizer) {
|
|
||||||
recognizer?.dispose();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handlePointerDown(PointerDownEvent event) {
|
void _handlePointerDown(PointerDownEvent event) {
|
||||||
if (_tap != null)
|
assert(_recognizers != null);
|
||||||
_tap.addPointer(event);
|
for (GestureRecognizer recognizer in _recognizers.values)
|
||||||
if (_doubleTap != null)
|
recognizer.addPointer(event);
|
||||||
_doubleTap.addPointer(event);
|
|
||||||
if (_longPress != null)
|
|
||||||
_longPress.addPointer(event);
|
|
||||||
if (_verticalDrag != null)
|
|
||||||
_verticalDrag.addPointer(event);
|
|
||||||
if (_horizontalDrag != null)
|
|
||||||
_horizontalDrag.addPointer(event);
|
|
||||||
if (_pan != null)
|
|
||||||
_pan.addPointer(event);
|
|
||||||
if (_scale != null)
|
|
||||||
_scale.addPointer(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HitTestBehavior get _defaultBehavior {
|
HitTestBehavior get _defaultBehavior {
|
||||||
@ -287,47 +346,21 @@ class _GestureDetectorState extends State<GestureDetector> {
|
|||||||
behavior: config.behavior ?? _defaultBehavior,
|
behavior: config.behavior ?? _defaultBehavior,
|
||||||
child: config.child
|
child: config.child
|
||||||
);
|
);
|
||||||
if (!config.excludeFromSemantics) {
|
if (!config.excludeFromSemantics)
|
||||||
result = new _GestureSemantics(
|
result = new _GestureSemantics(owner: this, child: result);
|
||||||
onTapDown: config.onTapDown,
|
|
||||||
onTapUp: config.onTapUp,
|
|
||||||
onTap: config.onTap,
|
|
||||||
onLongPress: config.onLongPress,
|
|
||||||
onVerticalDragStart: config.onVerticalDragStart,
|
|
||||||
onVerticalDragUpdate: config.onVerticalDragUpdate,
|
|
||||||
onVerticalDragEnd: config.onVerticalDragEnd,
|
|
||||||
onHorizontalDragStart: config.onHorizontalDragStart,
|
|
||||||
onHorizontalDragUpdate: config.onHorizontalDragUpdate,
|
|
||||||
onHorizontalDragEnd: config.onHorizontalDragEnd,
|
|
||||||
onPanStart: config.onPanStart,
|
|
||||||
onPanUpdate: config.onPanUpdate,
|
|
||||||
onPanEnd: config.onPanEnd,
|
|
||||||
child: result
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugFillDescription(List<String> description) {
|
void debugFillDescription(List<String> description) {
|
||||||
super.debugFillDescription(description);
|
super.debugFillDescription(description);
|
||||||
List<String> gestures = <String>[];
|
if (_recognizers == null) {
|
||||||
if (_tap != null)
|
description.add('DISPOSED');
|
||||||
gestures.add('tap');
|
} else {
|
||||||
if (_doubleTap != null)
|
List<String> gestures = _recognizers.values.map/*<String>*/((GestureRecognizer recognizer) => recognizer.toStringShort());
|
||||||
gestures.add('double tap');
|
if (gestures.isEmpty)
|
||||||
if (_longPress != null)
|
gestures.add('<none>');
|
||||||
gestures.add('long press');
|
description.add('gestures: ${gestures.join(", ")}');
|
||||||
if (_verticalDrag != null)
|
}
|
||||||
gestures.add('vertical drag');
|
|
||||||
if (_horizontalDrag != null)
|
|
||||||
gestures.add('horizontal drag');
|
|
||||||
if (_pan != null)
|
|
||||||
gestures.add('pan');
|
|
||||||
if (_scale != null)
|
|
||||||
gestures.add('scale');
|
|
||||||
if (gestures.isEmpty)
|
|
||||||
gestures.add('<none>');
|
|
||||||
description.add('gestures: ${gestures.join(", ")}');
|
|
||||||
switch (config.behavior) {
|
switch (config.behavior) {
|
||||||
case HitTestBehavior.translucent:
|
case HitTestBehavior.translucent:
|
||||||
description.add('behavior: translucent');
|
description.add('behavior: translucent');
|
||||||
@ -345,118 +378,99 @@ class _GestureDetectorState extends State<GestureDetector> {
|
|||||||
class _GestureSemantics extends OneChildRenderObjectWidget {
|
class _GestureSemantics extends OneChildRenderObjectWidget {
|
||||||
_GestureSemantics({
|
_GestureSemantics({
|
||||||
Key key,
|
Key key,
|
||||||
this.onTapDown,
|
Widget child,
|
||||||
this.onTapUp,
|
this.owner
|
||||||
this.onTap,
|
|
||||||
this.onLongPress,
|
|
||||||
this.onVerticalDragStart,
|
|
||||||
this.onVerticalDragUpdate,
|
|
||||||
this.onVerticalDragEnd,
|
|
||||||
this.onHorizontalDragStart,
|
|
||||||
this.onHorizontalDragUpdate,
|
|
||||||
this.onHorizontalDragEnd,
|
|
||||||
this.onPanStart,
|
|
||||||
this.onPanUpdate,
|
|
||||||
this.onPanEnd,
|
|
||||||
Widget child
|
|
||||||
}) : super(key: key, child: child);
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
final GestureTapDownCallback onTapDown;
|
final RawGestureDetectorState owner;
|
||||||
final GestureTapUpCallback onTapUp;
|
|
||||||
final GestureTapCallback onTap;
|
|
||||||
final GestureLongPressCallback onLongPress;
|
|
||||||
final GestureDragStartCallback onVerticalDragStart;
|
|
||||||
final GestureDragUpdateCallback onVerticalDragUpdate;
|
|
||||||
final GestureDragEndCallback onVerticalDragEnd;
|
|
||||||
final GestureDragStartCallback onHorizontalDragStart;
|
|
||||||
final GestureDragUpdateCallback onHorizontalDragUpdate;
|
|
||||||
final GestureDragEndCallback onHorizontalDragEnd;
|
|
||||||
final GesturePanStartCallback onPanStart;
|
|
||||||
final GesturePanUpdateCallback onPanUpdate;
|
|
||||||
final GesturePanEndCallback onPanEnd;
|
|
||||||
|
|
||||||
bool get _watchingTaps {
|
|
||||||
return onTapDown != null
|
|
||||||
|| onTapUp != null
|
|
||||||
|| onTap != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _watchingHorizontalDrags {
|
|
||||||
return onHorizontalDragStart != null
|
|
||||||
|| onHorizontalDragUpdate != null
|
|
||||||
|| onHorizontalDragEnd != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _watchingVerticalDrags {
|
|
||||||
return onVerticalDragStart != null
|
|
||||||
|| onVerticalDragUpdate != null
|
|
||||||
|| onVerticalDragEnd != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get _watchingPans {
|
|
||||||
return onPanStart != null
|
|
||||||
|| onPanUpdate != null
|
|
||||||
|| onPanEnd != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handleTap() {
|
void _handleTap() {
|
||||||
if (onTapDown != null)
|
TapGestureRecognizer recognizer = owner._recognizers[TapGestureRecognizer];
|
||||||
onTapDown(Point.origin);
|
assert(recognizer != null);
|
||||||
if (onTapUp != null)
|
if (recognizer.onTapDown != null)
|
||||||
onTapUp(Point.origin);
|
recognizer.onTapDown(Point.origin);
|
||||||
if (onTap != null)
|
if (recognizer.onTapUp != null)
|
||||||
onTap();
|
recognizer.onTapUp(Point.origin);
|
||||||
|
if (recognizer.onTap != null)
|
||||||
|
recognizer.onTap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleLongPress() {
|
||||||
|
LongPressGestureRecognizer recognizer = owner._recognizers[LongPressGestureRecognizer];
|
||||||
|
assert(recognizer != null);
|
||||||
|
if (recognizer.onLongPress != null)
|
||||||
|
recognizer.onLongPress();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleHorizontalDragUpdate(double delta) {
|
void _handleHorizontalDragUpdate(double delta) {
|
||||||
if (_watchingHorizontalDrags) {
|
{
|
||||||
if (onHorizontalDragStart != null)
|
HorizontalDragGestureRecognizer recognizer = owner._recognizers[HorizontalDragGestureRecognizer];
|
||||||
onHorizontalDragStart(Point.origin);
|
if (recognizer != null) {
|
||||||
if (onHorizontalDragUpdate != null)
|
if (recognizer.onStart != null)
|
||||||
onHorizontalDragUpdate(delta);
|
recognizer.onStart(Point.origin);
|
||||||
if (onHorizontalDragEnd != null)
|
if (recognizer.onUpdate != null)
|
||||||
onHorizontalDragEnd(Velocity.zero);
|
recognizer.onUpdate(delta);
|
||||||
} else {
|
if (recognizer.onEnd != null)
|
||||||
assert(_watchingPans);
|
recognizer.onEnd(Velocity.zero);
|
||||||
if (onPanStart != null)
|
return;
|
||||||
onPanStart(Point.origin);
|
}
|
||||||
if (onPanUpdate != null)
|
|
||||||
onPanUpdate(new Offset(delta, 0.0));
|
|
||||||
if (onPanEnd != null)
|
|
||||||
onPanEnd(Velocity.zero);
|
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
PanGestureRecognizer recognizer = owner._recognizers[PanGestureRecognizer];
|
||||||
|
if (recognizer != null) {
|
||||||
|
if (recognizer.onStart != null)
|
||||||
|
recognizer.onStart(Point.origin);
|
||||||
|
if (recognizer.onUpdate != null)
|
||||||
|
recognizer.onUpdate(new Offset(delta, 0.0));
|
||||||
|
if (recognizer.onEnd != null)
|
||||||
|
recognizer.onEnd(Velocity.zero);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleVerticalDragUpdate(double delta) {
|
void _handleVerticalDragUpdate(double delta) {
|
||||||
if (_watchingVerticalDrags) {
|
{
|
||||||
if (onVerticalDragStart != null)
|
VerticalDragGestureRecognizer recognizer = owner._recognizers[VerticalDragGestureRecognizer];
|
||||||
onVerticalDragStart(Point.origin);
|
if (recognizer != null) {
|
||||||
if (onVerticalDragUpdate != null)
|
if (recognizer.onStart != null)
|
||||||
onVerticalDragUpdate(delta);
|
recognizer.onStart(Point.origin);
|
||||||
if (onVerticalDragEnd != null)
|
if (recognizer.onUpdate != null)
|
||||||
onVerticalDragEnd(Velocity.zero);
|
recognizer.onUpdate(delta);
|
||||||
} else {
|
if (recognizer.onEnd != null)
|
||||||
assert(_watchingPans);
|
recognizer.onEnd(Velocity.zero);
|
||||||
if (onPanStart != null)
|
return;
|
||||||
onPanStart(Point.origin);
|
}
|
||||||
if (onPanUpdate != null)
|
|
||||||
onPanUpdate(new Offset(0.0, delta));
|
|
||||||
if (onPanEnd != null)
|
|
||||||
onPanEnd(Velocity.zero);
|
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
PanGestureRecognizer recognizer = owner._recognizers[PanGestureRecognizer];
|
||||||
|
if (recognizer != null) {
|
||||||
|
if (recognizer.onStart != null)
|
||||||
|
recognizer.onStart(Point.origin);
|
||||||
|
if (recognizer.onUpdate != null)
|
||||||
|
recognizer.onUpdate(new Offset(0.0, delta));
|
||||||
|
if (recognizer.onEnd != null)
|
||||||
|
recognizer.onEnd(Velocity.zero);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderSemanticsGestureHandler createRenderObject() => new RenderSemanticsGestureHandler(
|
RenderSemanticsGestureHandler createRenderObject() {
|
||||||
onTap: _watchingTaps ? _handleTap : null,
|
RenderSemanticsGestureHandler result = new RenderSemanticsGestureHandler();
|
||||||
onLongPress: onLongPress,
|
updateRenderObject(result, null);
|
||||||
onHorizontalDragUpdate: _watchingHorizontalDrags || _watchingPans ? _handleHorizontalDragUpdate : null,
|
return result;
|
||||||
onVerticalDragUpdate: _watchingVerticalDrags || _watchingPans ? _handleVerticalDragUpdate : null
|
}
|
||||||
);
|
|
||||||
|
|
||||||
void updateRenderObject(RenderSemanticsGestureHandler renderObject, _GestureSemantics oldWidget) {
|
void updateRenderObject(RenderSemanticsGestureHandler renderObject, _GestureSemantics oldWidget) {
|
||||||
renderObject.onTap = _watchingTaps ? _handleTap : null;
|
Map<Type, GestureRecognizer> recognizers = owner._recognizers;
|
||||||
renderObject.onLongPress = onLongPress;
|
renderObject.onTap = recognizers.containsKey(TapGestureRecognizer) ? _handleTap : null;
|
||||||
renderObject.onHorizontalDragUpdate = _watchingHorizontalDrags || _watchingPans ? _handleHorizontalDragUpdate : null;
|
renderObject.onLongPress = recognizers.containsKey(LongPressGestureRecognizer) ? _handleLongPress : null;
|
||||||
renderObject.onVerticalDragUpdate = _watchingVerticalDrags || _watchingPans ? _handleVerticalDragUpdate : null;
|
renderObject.onHorizontalDragUpdate = recognizers.containsKey(VerticalDragGestureRecognizer) ||
|
||||||
|
recognizers.containsKey(PanGestureRecognizer) ? _handleHorizontalDragUpdate : null;
|
||||||
|
renderObject.onVerticalDragUpdate = recognizers.containsKey(VerticalDragGestureRecognizer) ||
|
||||||
|
recognizers.containsKey(PanGestureRecognizer) ? _handleVerticalDragUpdate : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user