Fix iOS last up event velocity calculation - version 3 (#11571)

* Add synthesized property to pointer events

* test
This commit is contained in:
xster
2017-08-09 17:39:59 -07:00
committed by GitHub
parent 680d581db7
commit c9b0b3bb03
6 changed files with 66 additions and 11 deletions

View File

@@ -170,7 +170,8 @@ class PointerEventConverter {
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
tilt: datum.tilt,
synthesized: true,
);
state.lastPosition = position;
}
@@ -257,7 +258,8 @@ class PointerEventConverter {
radiusMin: datum.radiusMin,
radiusMax: datum.radiusMax,
orientation: datum.orientation,
tilt: datum.tilt
tilt: datum.tilt,
synthesized: true,
);
state.lastPosition = position;
}

View File

@@ -113,7 +113,8 @@ abstract class PointerEvent {
this.radiusMin: 0.0,
this.radiusMax: 0.0,
this.orientation: 0.0,
this.tilt: 0.0
this.tilt: 0.0,
this.synthesized: false,
});
/// Time of event dispatch, relative to an arbitrary timeline.
@@ -235,6 +236,18 @@ abstract class PointerEvent {
/// the stylus is flat on that surface).
final double tilt;
/// We occasionally synthesize PointerEvents that aren't exact translations
/// of [ui.PointerData] from the engine to cover small cross-OS discrepancies
/// in pointer behaviours.
///
/// For instance, on end events, Android always drops any location changes
/// that happened between its reporting intervals when emiting the end events.
///
/// On iOS, minor incorrect location changes from the previous move events
/// can be reported on end events. We synthesize a [PointerEvent] to cover
/// the difference between the 2 events in that case.
final bool synthesized;
@override
String toString() => '$runtimeType($position)';
@@ -261,7 +274,8 @@ abstract class PointerEvent {
'radiusMin: $radiusMin, '
'radiusMax: $radiusMax, '
'orientation: $orientation, '
'tilt: $tilt'
'tilt: $tilt, '
'synthesized: $synthesized'
')';
}
}
@@ -365,7 +379,8 @@ class PointerHoverEvent extends PointerEvent {
double radiusMin: 0.0,
double radiusMax: 0.0,
double orientation: 0.0,
double tilt: 0.0
double tilt: 0.0,
bool synthesized: false,
}) : super(
timeStamp: timeStamp,
kind: kind,
@@ -384,7 +399,8 @@ class PointerHoverEvent extends PointerEvent {
radiusMin: radiusMin,
radiusMax: radiusMax,
orientation: orientation,
tilt: tilt
tilt: tilt,
synthesized: synthesized,
);
}
@@ -463,7 +479,8 @@ class PointerMoveEvent extends PointerEvent {
double radiusMin: 0.0,
double radiusMax: 0.0,
double orientation: 0.0,
double tilt: 0.0
double tilt: 0.0,
bool synthesized: false,
}) : super(
timeStamp: timeStamp,
pointer: pointer,
@@ -484,7 +501,8 @@ class PointerMoveEvent extends PointerEvent {
radiusMin: radiusMin,
radiusMax: radiusMax,
orientation: orientation,
tilt: tilt
tilt: tilt,
synthesized: synthesized,
);
}

View File

@@ -130,7 +130,8 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
if (event is PointerMoveEvent) {
final VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
tracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
tracker.addPosition(event.timeStamp, event.position);
final Offset delta = event.delta;
if (_state == _DragState.accepted) {
if (onUpdate != null) {

View File

@@ -62,7 +62,8 @@ abstract class MultiDragPointerState {
void _move(PointerMoveEvent event) {
assert(_arenaEntry != null);
_velocityTracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
_velocityTracker.addPosition(event.timeStamp, event.position);
if (_client != null) {
assert(pendingDelta == null);
// Call client last to avoid reentrancy.

View File

@@ -152,7 +152,8 @@ class ScaleGestureRecognizer extends OneSequenceGestureRecognizer {
if (event is PointerMoveEvent) {
final VelocityTracker tracker = _velocityTrackers[event.pointer];
assert(tracker != null);
tracker.addPosition(event.timeStamp, event.position);
if (!event.synthesized)
tracker.addPosition(event.timeStamp, event.position);
_pointerLocations[event.pointer] = event.position;
shouldStartIfAccepted = true;
} else if (event is PointerDownEvent) {

View File

@@ -236,6 +236,38 @@ void main() {
drag.dispose();
});
testGesture('Synthesized pointer events are ignored for velocity tracking', (GestureTester tester) {
final HorizontalDragGestureRecognizer drag = new HorizontalDragGestureRecognizer();
Velocity velocity;
drag.onEnd = (DragEndDetails details) {
velocity = details.velocity;
};
final TestPointer pointer = new TestPointer(1);
final PointerDownEvent down = pointer.down(const Offset(10.0, 25.0), timeStamp: const Duration(milliseconds: 10));
drag.addPointer(down);
tester.closeArena(1);
tester.route(down);
tester.route(pointer.move(const Offset(20.0, 25.0), timeStamp: const Duration(milliseconds: 20)));
tester.route(pointer.move(const Offset(30.0, 25.0), timeStamp: const Duration(milliseconds: 30)));
tester.route(pointer.move(const Offset(40.0, 25.0), timeStamp: const Duration(milliseconds: 40)));
tester.route(pointer.move(const Offset(50.0, 25.0), timeStamp: const Duration(milliseconds: 50)));
tester.route(new PointerMoveEvent(
pointer: 1,
// Simulate a small synthesized wobble which would have slowed down the
// horizontal velocity from 1 px/ms and introduced a slight vertical velocity.
position: const Offset(51.0, 26.0),
timeStamp: const Duration(milliseconds: 60),
synthesized: true,
));
tester.route(pointer.up(timeStamp: const Duration(milliseconds: 20)));
expect(velocity.pixelsPerSecond.dx, moreOrLessEquals(1000.0));
expect(velocity.pixelsPerSecond.dy, moreOrLessEquals(0.0));
drag.dispose();
});
testGesture('Drag details', (GestureTester tester) {
expect(new DragDownDetails(), hasOneLineDescription);
expect(new DragStartDetails(), hasOneLineDescription);