First pass at support for pinch gestures; panning issues (needs testing)
Conflicts: sky/packages/sky/lib/gestures/drag.dart
This commit is contained in:
parent
f55a6ad1c1
commit
842e94e9f8
@ -17,6 +17,8 @@ const double kEdgeSlop = 12.0; // Logical pixels
|
||||
const double kTouchSlop = 8.0; // Logical pixels
|
||||
const double kDoubleTapTouchSlop = kTouchSlop; // Logical pixels
|
||||
const double kPagingTouchSlop = kTouchSlop * 2.0; // Logical pixels
|
||||
const double kPanSlop = kTouchSlop * 2.0; // Logical pixels
|
||||
const double kPinchSlop = kTouchSlop; // Logical pixels
|
||||
const double kDoubleTapSlop = 100.0; // Logical pixels
|
||||
const double kWindowTouchSlop = 16.0; // Logical pixels
|
||||
const double kMinFlingVelocity = 50.0; // Logical pixels / second
|
||||
|
@ -79,7 +79,7 @@ abstract class _DragGestureRecognizer<T extends dynamic> extends GestureRecogniz
|
||||
if (_state != DragState.accepted) {
|
||||
_state = DragState.accepted;
|
||||
T delta = _pendingDragDelta;
|
||||
_pendingDragDelta = null;
|
||||
_pendingDragDelta = _initialPendingDragDelta;
|
||||
if (onStart != null)
|
||||
onStart();
|
||||
if (delta != _initialPendingDragDelta && onUpdate != null)
|
||||
@ -149,6 +149,6 @@ class PanGestureRecognizer extends _DragGestureRecognizer<sky.Offset> {
|
||||
sky.Offset get _initialPendingDragDelta => sky.Offset.zero;
|
||||
sky.Offset _getDragDelta(sky.PointerEvent event) => new sky.Offset(event.dx, event.dy);
|
||||
bool get _hasSufficientPendingDragDeltaToAccept {
|
||||
return _pendingDragDelta.dx.abs() > kTouchSlop || _pendingDragDelta.dy.abs() > kTouchSlop;
|
||||
return _pendingDragDelta.distance > kPanSlop;
|
||||
}
|
||||
}
|
||||
|
139
packages/flutter/lib/gestures/pinch.dart
Normal file
139
packages/flutter/lib/gestures/pinch.dart
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'dart:sky' as sky;
|
||||
|
||||
import 'package:sky/gestures/arena.dart';
|
||||
import 'package:sky/gestures/recognizer.dart';
|
||||
import 'package:sky/gestures/constants.dart';
|
||||
|
||||
enum PinchState {
|
||||
ready,
|
||||
possible,
|
||||
started,
|
||||
ended
|
||||
}
|
||||
|
||||
typedef void GesturePinchStartCallback();
|
||||
typedef void GesturePinchUpdateCallback(double scale);
|
||||
typedef void GesturePinchEndCallback();
|
||||
|
||||
class PinchGestureRecognizer extends GestureRecognizer {
|
||||
PinchGestureRecognizer({ PointerRouter router, this.onStart, this.onUpdate, this.onEnd })
|
||||
: super(router: router);
|
||||
|
||||
GesturePinchStartCallback onStart;
|
||||
GesturePinchUpdateCallback onUpdate;
|
||||
GesturePinchEndCallback onEnd;
|
||||
|
||||
PinchState _state = PinchState.ready;
|
||||
|
||||
double _initialSpan;
|
||||
double _currentSpan;
|
||||
Map<int, sky.Point> _pointerLocations;
|
||||
|
||||
double get _scaleFactor => _initialSpan > 0 ? _currentSpan / _initialSpan : 1.0;
|
||||
|
||||
void addPointer(sky.PointerEvent event) {
|
||||
startTrackingPointer(event.pointer);
|
||||
if (_state == PinchState.ready) {
|
||||
_state = PinchState.possible;
|
||||
_initialSpan = 0.0;
|
||||
_currentSpan = 0.0;
|
||||
_pointerLocations = new Map<int, sky.Point>();
|
||||
}
|
||||
}
|
||||
|
||||
void handleEvent(sky.PointerEvent event) {
|
||||
assert(_state != PinchState.ready);
|
||||
bool configChanged = false;
|
||||
switch(event.type) {
|
||||
case 'pointerup':
|
||||
configChanged = true;
|
||||
_pointerLocations.remove(event.pointer);
|
||||
break;
|
||||
case 'pointerdown':
|
||||
configChanged = true;
|
||||
_pointerLocations[event.pointer] = new sky.Point(event.x, event.y);
|
||||
break;
|
||||
case 'pointermove':
|
||||
_pointerLocations[event.pointer] = new sky.Point(event.x, event.y);
|
||||
break;
|
||||
}
|
||||
|
||||
int count = _pointerLocations.keys.length;
|
||||
|
||||
// Compute the focal point
|
||||
sky.Point focalPoint = sky.Point.origin;
|
||||
for (int pointer in _pointerLocations.keys)
|
||||
focalPoint += _pointerLocations[pointer].toOffset();
|
||||
focalPoint = new sky.Point(focalPoint.x / count, focalPoint.y / count);
|
||||
|
||||
// Span is the average deviation from focal point
|
||||
double totalDeviation = 0.0;
|
||||
for (int pointer in _pointerLocations.keys)
|
||||
totalDeviation += (focalPoint - _pointerLocations[pointer]).distance;
|
||||
_currentSpan = count > 0 ? totalDeviation / count : 0.0;
|
||||
|
||||
if (configChanged) {
|
||||
_initialSpan = _currentSpan;
|
||||
if (_state == PinchState.started) {
|
||||
_state = PinchState.ended;
|
||||
if (onEnd != null)
|
||||
onEnd();
|
||||
}
|
||||
}
|
||||
|
||||
if (_state == PinchState.ready)
|
||||
_state = PinchState.possible;
|
||||
|
||||
if (_state == PinchState.possible &&
|
||||
(_currentSpan - _initialSpan).abs() > kPinchSlop) {
|
||||
resolve(GestureDisposition.accepted);
|
||||
}
|
||||
|
||||
if (_state == PinchState.ended && _currentSpan != _initialSpan) {
|
||||
_state = PinchState.started;
|
||||
if (onStart != null)
|
||||
onStart();
|
||||
}
|
||||
|
||||
if (_state == PinchState.started && onUpdate != null)
|
||||
onUpdate(_scaleFactor);
|
||||
|
||||
stopTrackingIfPointerNoLongerDown(event);
|
||||
}
|
||||
|
||||
void acceptGesture(int pointer) {
|
||||
if (_state != PinchState.started) {
|
||||
_state = PinchState.started;
|
||||
if (onStart != null)
|
||||
onStart();
|
||||
if (onUpdate != null)
|
||||
onUpdate(_scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
void didStopTrackingLastPointer(int pointer) {
|
||||
switch(_state) {
|
||||
case PinchState.possible:
|
||||
resolve(GestureDisposition.rejected);
|
||||
break;
|
||||
case PinchState.ready:
|
||||
assert(false);
|
||||
break;
|
||||
case PinchState.started:
|
||||
assert(false);
|
||||
break;
|
||||
case PinchState.ended:
|
||||
break;
|
||||
}
|
||||
_state = PinchState.ready;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import 'dart:sky' as sky;
|
||||
|
||||
import 'package:sky/gestures/drag.dart';
|
||||
import 'package:sky/gestures/long_press.dart';
|
||||
import 'package:sky/gestures/pinch.dart';
|
||||
import 'package:sky/gestures/recognizer.dart';
|
||||
import 'package:sky/gestures/show_press.dart';
|
||||
import 'package:sky/gestures/tap.dart';
|
||||
@ -27,7 +28,10 @@ class GestureDetector extends StatefulComponent {
|
||||
this.onHorizontalDragEnd,
|
||||
this.onPanStart,
|
||||
this.onPanUpdate,
|
||||
this.onPanEnd
|
||||
this.onPanEnd,
|
||||
this.onPinchStart,
|
||||
this.onPinchUpdate,
|
||||
this.onPinchEnd
|
||||
}) : super(key: key);
|
||||
|
||||
Widget child;
|
||||
@ -47,6 +51,10 @@ class GestureDetector extends StatefulComponent {
|
||||
GesturePanUpdateCallback onPanUpdate;
|
||||
GesturePanEndCallback onPanEnd;
|
||||
|
||||
GesturePinchStartCallback onPinchStart;
|
||||
GesturePinchUpdateCallback onPinchUpdate;
|
||||
GesturePinchEndCallback onPinchEnd;
|
||||
|
||||
void syncConstructorArguments(GestureDetector source) {
|
||||
child = source.child;
|
||||
onTap = source.onTap;
|
||||
@ -61,6 +69,9 @@ class GestureDetector extends StatefulComponent {
|
||||
onPanStart = source.onPanStart;
|
||||
onPanUpdate = source.onPanUpdate;
|
||||
onPanEnd = source.onPanEnd;
|
||||
onPinchStart = source.onPinchStart;
|
||||
onPinchUpdate = source.onPinchUpdate;
|
||||
onPinchEnd = source.onPinchEnd;
|
||||
_syncGestureListeners();
|
||||
}
|
||||
|
||||
@ -108,6 +119,13 @@ class GestureDetector extends StatefulComponent {
|
||||
return _pan;
|
||||
}
|
||||
|
||||
PinchGestureRecognizer _pinch;
|
||||
PinchGestureRecognizer _ensurePinch() {
|
||||
if (_pinch == null)
|
||||
_pinch = new PinchGestureRecognizer(router: _router);
|
||||
return _pinch;
|
||||
}
|
||||
|
||||
void didMount() {
|
||||
super.didMount();
|
||||
_syncGestureListeners();
|
||||
@ -121,6 +139,7 @@ class GestureDetector extends StatefulComponent {
|
||||
_verticalDrag = _ensureDisposed(_verticalDrag);
|
||||
_horizontalDrag = _ensureDisposed(_horizontalDrag);
|
||||
_pan = _ensureDisposed(_pan);
|
||||
_pinch = _ensureDisposed(_pinch);
|
||||
}
|
||||
|
||||
void _syncGestureListeners() {
|
||||
@ -130,6 +149,7 @@ class GestureDetector extends StatefulComponent {
|
||||
_syncVerticalDrag();
|
||||
_syncHorizontalDrag();
|
||||
_syncPan();
|
||||
_syncPinch();
|
||||
}
|
||||
|
||||
void _syncTap() {
|
||||
@ -186,6 +206,17 @@ class GestureDetector extends StatefulComponent {
|
||||
}
|
||||
}
|
||||
|
||||
void _syncPinch() {
|
||||
if (onPinchStart == null && onPinchUpdate == null && onPinchEnd == null) {
|
||||
_pinch = _ensureDisposed(_pan);
|
||||
} else {
|
||||
_ensurePinch()
|
||||
..onStart = onPinchStart
|
||||
..onUpdate = onPinchUpdate
|
||||
..onEnd = onPinchEnd;
|
||||
}
|
||||
}
|
||||
|
||||
GestureRecognizer _ensureDisposed(GestureRecognizer recognizer) {
|
||||
recognizer?.dispose();
|
||||
return null;
|
||||
@ -204,6 +235,8 @@ class GestureDetector extends StatefulComponent {
|
||||
_horizontalDrag.addPointer(event);
|
||||
if (_pan != null)
|
||||
_pan.addPointer(event);
|
||||
if (_pinch != null)
|
||||
_pinch.addPointer(event);
|
||||
return EventDisposition.processed;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user