mirror of
https://github.com/flutter/flutter.git
synced 2026-02-04 19:00:09 +08:00
Resolving and piping the view ID through the WidgetController and the TestPointer so that clicks wind up on the right view (#178941)
## What's new? - While coming up with a scheme for testing multi-window, I realize that issuing taps in `testWidgets` across views was not working because the view was always being set to `0` - The fix is to resolve the view when we can, and provide an optional view in the other methods ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
This commit is contained in:
parent
804fe2f3e2
commit
a99fb28619
@ -7,6 +7,8 @@ import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
test('Should route pointers', () {
|
||||
var callbackRan = false;
|
||||
void callback(PointerEvent event) {
|
||||
|
||||
@ -776,9 +776,24 @@ abstract class WidgetController {
|
||||
}
|
||||
|
||||
FlutterView _viewOf(finders.FinderBase<Element> finder) {
|
||||
return firstWidget<View>(
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
if (view == null) {
|
||||
throw StateError(
|
||||
'No FlutterView ancestor found for finder: '
|
||||
'${finder.toString(describeSelf: true)}',
|
||||
);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
FlutterView? _maybeViewOf(finders.FinderBase<Element> finder) {
|
||||
final Iterable<View> views = widgetList<View>(
|
||||
finders.find.ancestor(of: finder, matching: finders.find.byType(View)),
|
||||
).view;
|
||||
);
|
||||
if (views.isEmpty) {
|
||||
return null;
|
||||
}
|
||||
return views.first.view;
|
||||
}
|
||||
|
||||
/// Checks if `finder` exists in the tree.
|
||||
@ -1041,11 +1056,13 @@ abstract class WidgetController {
|
||||
bool warnIfMissed = true,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return tapAt(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'tap'),
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1097,7 +1114,7 @@ abstract class WidgetController {
|
||||
),
|
||||
]);
|
||||
}
|
||||
return tapAt(tapLocation, pointer: pointer, buttons: buttons);
|
||||
return tapAt(tapLocation, pointer: pointer, buttons: buttons, view: ranges.single.view.view);
|
||||
}
|
||||
|
||||
/// Dispatch a pointer down / pointer up sequence at the given location.
|
||||
@ -1106,6 +1123,7 @@ abstract class WidgetController {
|
||||
int? pointer,
|
||||
int buttons = kPrimaryButton,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
final TestGesture gesture = await startGesture(
|
||||
@ -1113,6 +1131,7 @@ abstract class WidgetController {
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
await gesture.up();
|
||||
});
|
||||
@ -1138,12 +1157,14 @@ abstract class WidgetController {
|
||||
bool warnIfMissed = true,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return TestAsyncUtils.guard<TestGesture>(() {
|
||||
return startGesture(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'press'),
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -1167,11 +1188,13 @@ abstract class WidgetController {
|
||||
bool warnIfMissed = true,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return longPressAt(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'longPress'),
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1182,6 +1205,7 @@ abstract class WidgetController {
|
||||
int? pointer,
|
||||
int buttons = kPrimaryButton,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
final TestGesture gesture = await startGesture(
|
||||
@ -1189,6 +1213,7 @@ abstract class WidgetController {
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
await pump(kLongPressTimeout + kPressTimeout);
|
||||
await gesture.up();
|
||||
@ -1253,6 +1278,7 @@ abstract class WidgetController {
|
||||
bool warnIfMissed = true,
|
||||
PointerDeviceKind deviceKind = PointerDeviceKind.touch,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return flingFrom(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'fling'),
|
||||
offset,
|
||||
@ -1263,6 +1289,7 @@ abstract class WidgetController {
|
||||
initialOffset: initialOffset,
|
||||
initialOffsetDelay: initialOffsetDelay,
|
||||
deviceKind: deviceKind,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1283,6 +1310,7 @@ abstract class WidgetController {
|
||||
Offset initialOffset = Offset.zero,
|
||||
Duration initialOffsetDelay = const Duration(seconds: 1),
|
||||
PointerDeviceKind deviceKind = PointerDeviceKind.touch,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(offset.distance > 0.0);
|
||||
assert(speed > 0.0); // speed is pixels/second
|
||||
@ -1294,7 +1322,11 @@ abstract class WidgetController {
|
||||
var timeStamp = 0.0;
|
||||
var lastTimeStamp = timeStamp;
|
||||
await sendEventToBinding(
|
||||
testPointer.down(startLocation, timeStamp: Duration(microseconds: timeStamp.round())),
|
||||
testPointer.down(
|
||||
startLocation,
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
if (initialOffset.distance > 0.0) {
|
||||
await sendEventToBinding(
|
||||
@ -1310,7 +1342,11 @@ abstract class WidgetController {
|
||||
final Offset location =
|
||||
startLocation + initialOffset + Offset.lerp(Offset.zero, offset, i / kMoveCount)!;
|
||||
await sendEventToBinding(
|
||||
testPointer.move(location, timeStamp: Duration(microseconds: timeStamp.round())),
|
||||
testPointer.move(
|
||||
location,
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
timeStamp += timeStampDelta;
|
||||
if (timeStamp - lastTimeStamp > frameInterval.inMicroseconds) {
|
||||
@ -1319,7 +1355,10 @@ abstract class WidgetController {
|
||||
}
|
||||
}
|
||||
await sendEventToBinding(
|
||||
testPointer.up(timeStamp: Duration(microseconds: timeStamp.round())),
|
||||
testPointer.up(
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -1345,6 +1384,7 @@ abstract class WidgetController {
|
||||
Duration initialOffsetDelay = const Duration(seconds: 1),
|
||||
bool warnIfMissed = true,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return trackpadFlingFrom(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'fling'),
|
||||
offset,
|
||||
@ -1354,6 +1394,7 @@ abstract class WidgetController {
|
||||
frameInterval: frameInterval,
|
||||
initialOffset: initialOffset,
|
||||
initialOffsetDelay: initialOffsetDelay,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1374,6 +1415,7 @@ abstract class WidgetController {
|
||||
Duration frameInterval = const Duration(milliseconds: 16),
|
||||
Offset initialOffset = Offset.zero,
|
||||
Duration initialOffsetDelay = const Duration(seconds: 1),
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(offset.distance > 0.0);
|
||||
assert(speed > 0.0); // speed is pixels/second
|
||||
@ -1393,6 +1435,7 @@ abstract class WidgetController {
|
||||
testPointer.panZoomStart(
|
||||
startLocation,
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
if (initialOffset.distance > 0.0) {
|
||||
@ -1401,6 +1444,7 @@ abstract class WidgetController {
|
||||
startLocation,
|
||||
pan: initialOffset,
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
timeStamp += initialOffsetDelay.inMicroseconds;
|
||||
@ -1413,6 +1457,7 @@ abstract class WidgetController {
|
||||
startLocation,
|
||||
pan: pan,
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
timeStamp += timeStampDelta;
|
||||
@ -1422,7 +1467,10 @@ abstract class WidgetController {
|
||||
}
|
||||
}
|
||||
await sendEventToBinding(
|
||||
testPointer.panZoomEnd(timeStamp: Duration(microseconds: timeStamp.round())),
|
||||
testPointer.panZoomEnd(
|
||||
timeStamp: Duration(microseconds: timeStamp.round()),
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -1532,6 +1580,7 @@ abstract class WidgetController {
|
||||
bool warnIfMissed = true,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
}) {
|
||||
final FlutterView? view = _maybeViewOf(finder);
|
||||
return dragFrom(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'drag'),
|
||||
offset,
|
||||
@ -1540,6 +1589,7 @@ abstract class WidgetController {
|
||||
touchSlopX: touchSlopX,
|
||||
touchSlopY: touchSlopY,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1562,6 +1612,7 @@ abstract class WidgetController {
|
||||
double touchSlopX = kDragSlopDefault,
|
||||
double touchSlopY = kDragSlopDefault,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(kDragSlopDefault > kTouchSlop);
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
@ -1570,6 +1621,7 @@ abstract class WidgetController {
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
kind: kind,
|
||||
view: view,
|
||||
);
|
||||
|
||||
final double xSign = offset.dx.sign;
|
||||
@ -1597,17 +1649,20 @@ abstract class WidgetController {
|
||||
final double diffY = offsetSlope.abs() * touchSlopX * ySign;
|
||||
|
||||
// The vector from the origin to the vertical edge.
|
||||
await gesture.moveBy(Offset(signedSlopX, diffY));
|
||||
await gesture.moveBy(Offset(signedSlopX, diffY), view: view);
|
||||
if (offsetY.abs() <= touchSlopY) {
|
||||
// The drag ends on or before getting to the horizontal extension of the horizontal edge.
|
||||
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY));
|
||||
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY), view: view);
|
||||
} else {
|
||||
final double diffY2 = signedSlopY - diffY;
|
||||
final double diffX2 = inverseOffsetSlope * diffY2;
|
||||
|
||||
// The vector from the edge of the box to the horizontal extension of the horizontal edge.
|
||||
await gesture.moveBy(Offset(diffX2, diffY2));
|
||||
await gesture.moveBy(Offset(offsetX - diffX2 - signedSlopX, offsetY - signedSlopY));
|
||||
await gesture.moveBy(Offset(diffX2, diffY2), view: view);
|
||||
await gesture.moveBy(
|
||||
Offset(offsetX - diffX2 - signedSlopX, offsetY - signedSlopY),
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert(offsetY.abs() > touchSlopY);
|
||||
@ -1616,29 +1671,32 @@ abstract class WidgetController {
|
||||
final double diffX = inverseOffsetSlope.abs() * touchSlopY * xSign;
|
||||
|
||||
// The vector from the origin to the vertical edge.
|
||||
await gesture.moveBy(Offset(diffX, signedSlopY));
|
||||
await gesture.moveBy(Offset(diffX, signedSlopY), view: view);
|
||||
if (offsetX.abs() <= touchSlopX) {
|
||||
// The drag ends on or before getting to the vertical extension of the vertical edge.
|
||||
await gesture.moveBy(Offset(offsetX - diffX, offsetY - signedSlopY));
|
||||
await gesture.moveBy(Offset(offsetX - diffX, offsetY - signedSlopY), view: view);
|
||||
} else {
|
||||
final double diffX2 = signedSlopX - diffX;
|
||||
final double diffY2 = offsetSlope * diffX2;
|
||||
|
||||
// The vector from the edge of the box to the vertical extension of the vertical edge.
|
||||
await gesture.moveBy(Offset(diffX2, diffY2));
|
||||
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - diffY2 - signedSlopY));
|
||||
await gesture.moveBy(Offset(diffX2, diffY2), view: view);
|
||||
await gesture.moveBy(
|
||||
Offset(offsetX - signedSlopX, offsetY - diffY2 - signedSlopY),
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The drag goes through the corner of the box.
|
||||
await gesture.moveBy(Offset(signedSlopX, signedSlopY));
|
||||
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - signedSlopY));
|
||||
await gesture.moveBy(Offset(signedSlopX, signedSlopY), view: view);
|
||||
await gesture.moveBy(Offset(offsetX - signedSlopX, offsetY - signedSlopY), view: view);
|
||||
}
|
||||
} else {
|
||||
// The drag ends inside the box.
|
||||
await gesture.moveBy(offset);
|
||||
await gesture.moveBy(offset, view: view);
|
||||
}
|
||||
await gesture.up();
|
||||
await gesture.up(view: view);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1670,6 +1728,7 @@ abstract class WidgetController {
|
||||
int buttons = kPrimaryButton,
|
||||
double frequency = 60.0,
|
||||
bool warnIfMissed = true,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
return timedDragFrom(
|
||||
getCenter(finder, warnIfMissed: warnIfMissed, callee: 'timedDrag'),
|
||||
@ -1678,6 +1737,7 @@ abstract class WidgetController {
|
||||
pointer: pointer,
|
||||
buttons: buttons,
|
||||
frequency: frequency,
|
||||
view: view,
|
||||
);
|
||||
}
|
||||
|
||||
@ -1696,6 +1756,7 @@ abstract class WidgetController {
|
||||
int? pointer,
|
||||
int buttons = kPrimaryButton,
|
||||
double frequency = 60.0,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(frequency > 0);
|
||||
final int intervals = duration.inMicroseconds * frequency ~/ 1E6;
|
||||
@ -1710,13 +1771,18 @@ abstract class WidgetController {
|
||||
];
|
||||
final records = <PointerEventRecord>[
|
||||
PointerEventRecord(Duration.zero, <PointerEvent>[
|
||||
PointerAddedEvent(position: startLocation),
|
||||
PointerAddedEvent(
|
||||
position: startLocation,
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
),
|
||||
PointerDownEvent(position: startLocation, pointer: pointer, buttons: buttons),
|
||||
]),
|
||||
...<PointerEventRecord>[
|
||||
for (int t = 0; t <= intervals; t += 1)
|
||||
PointerEventRecord(timeStamps[t], <PointerEvent>[
|
||||
PointerMoveEvent(
|
||||
viewId:
|
||||
view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamps[t],
|
||||
position: offsets[t + 1],
|
||||
delta: offsets[t + 1] - offsets[t],
|
||||
@ -1727,6 +1793,7 @@ abstract class WidgetController {
|
||||
],
|
||||
PointerEventRecord(duration, <PointerEvent>[
|
||||
PointerUpEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: duration,
|
||||
position: offsets.last,
|
||||
pointer: pointer,
|
||||
@ -1802,12 +1869,13 @@ abstract class WidgetController {
|
||||
int? pointer,
|
||||
PointerDeviceKind kind = PointerDeviceKind.touch,
|
||||
int buttons = kPrimaryButton,
|
||||
FlutterView? view,
|
||||
}) async {
|
||||
final TestGesture result = _createGesture(pointer: pointer, kind: kind, buttons: buttons);
|
||||
if (kind == PointerDeviceKind.trackpad) {
|
||||
await result.panZoomStart(downLocation);
|
||||
await result.panZoomStart(downLocation, view: view);
|
||||
} else {
|
||||
await result.down(downLocation);
|
||||
await result.down(downLocation, view: view);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
/// @docImport 'widget_tester.dart';
|
||||
library;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'test_async_utils.dart';
|
||||
|
||||
@ -121,7 +121,12 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the set of buttons in the last down or move event is used.
|
||||
/// You can give a specific set of buttons by passing the `buttons` argument.
|
||||
PointerDownEvent down(Offset newLocation, {Duration timeStamp = Duration.zero, int? buttons}) {
|
||||
PointerDownEvent down(
|
||||
Offset newLocation, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
int? buttons,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(!isDown);
|
||||
assert(!isPanZoomActive);
|
||||
_isDown = true;
|
||||
@ -130,6 +135,7 @@ class TestPointer {
|
||||
_buttons = buttons;
|
||||
}
|
||||
return PointerDownEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -149,7 +155,12 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the set of buttons in the last down or move event is used.
|
||||
/// You can give a specific set of buttons by passing the `buttons` argument.
|
||||
PointerMoveEvent move(Offset newLocation, {Duration timeStamp = Duration.zero, int? buttons}) {
|
||||
PointerMoveEvent move(
|
||||
Offset newLocation, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
int? buttons,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(
|
||||
isDown,
|
||||
'Move events can only be generated when the pointer is down. To '
|
||||
@ -164,6 +175,7 @@ class TestPointer {
|
||||
}
|
||||
return PointerMoveEvent(
|
||||
timeStamp: timeStamp,
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
pointer: pointer,
|
||||
@ -179,11 +191,12 @@ class TestPointer {
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
///
|
||||
/// The object is no longer usable after this method has been called.
|
||||
PointerUpEvent up({Duration timeStamp = Duration.zero}) {
|
||||
PointerUpEvent up({Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(!isPanZoomActive);
|
||||
assert(isDown);
|
||||
_isDown = false;
|
||||
return PointerUpEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -198,11 +211,12 @@ class TestPointer {
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
///
|
||||
/// The object is no longer usable after this method has been called.
|
||||
PointerCancelEvent cancel({Duration timeStamp = Duration.zero}) {
|
||||
PointerCancelEvent cancel({Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(isDown);
|
||||
_isDown = false;
|
||||
return PointerCancelEvent(
|
||||
timeStamp: timeStamp,
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
pointer: pointer,
|
||||
@ -215,9 +229,14 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerAddedEvent addPointer({Duration timeStamp = Duration.zero, Offset? location}) {
|
||||
PointerAddedEvent addPointer({
|
||||
Duration timeStamp = Duration.zero,
|
||||
Offset? location,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
_location = location ?? _location;
|
||||
return PointerAddedEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -230,9 +249,14 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerRemovedEvent removePointer({Duration timeStamp = Duration.zero, Offset? location}) {
|
||||
PointerRemovedEvent removePointer({
|
||||
Duration timeStamp = Duration.zero,
|
||||
Offset? location,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
_location = location ?? _location;
|
||||
return PointerRemovedEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -248,7 +272,11 @@ class TestPointer {
|
||||
///
|
||||
/// [isDown] must be false, since hover events can't be sent when the pointer
|
||||
/// is up.
|
||||
PointerHoverEvent hover(Offset newLocation, {Duration timeStamp = Duration.zero}) {
|
||||
PointerHoverEvent hover(
|
||||
Offset newLocation, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(
|
||||
!isDown,
|
||||
'Hover events can only be generated when the pointer is up. To '
|
||||
@ -257,6 +285,7 @@ class TestPointer {
|
||||
final Offset delta = location != null ? newLocation - location! : Offset.zero;
|
||||
_location = newLocation;
|
||||
return PointerHoverEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -275,10 +304,12 @@ class TestPointer {
|
||||
Offset scrollDelta, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
RespondPointerEventCallback? onRespond,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(kind != PointerDeviceKind.touch, "Touch pointers can't generate pointer signal events");
|
||||
assert(location != null);
|
||||
return PointerScrollEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -292,10 +323,14 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerScrollInertiaCancelEvent scrollInertiaCancel({Duration timeStamp = Duration.zero}) {
|
||||
PointerScrollInertiaCancelEvent scrollInertiaCancel({
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(kind != PointerDeviceKind.touch, "Touch pointers can't generate pointer signal events");
|
||||
assert(location != null);
|
||||
return PointerScrollInertiaCancelEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -307,10 +342,11 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerScaleEvent scale(double scale, {Duration timeStamp = Duration.zero}) {
|
||||
PointerScaleEvent scale(double scale, {Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(kind != PointerDeviceKind.touch, "Touch pointers can't generate pointer signal events");
|
||||
assert(location != null);
|
||||
return PointerScaleEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
kind: kind,
|
||||
device: _device,
|
||||
@ -324,13 +360,18 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerPanZoomStartEvent panZoomStart(Offset location, {Duration timeStamp = Duration.zero}) {
|
||||
PointerPanZoomStartEvent panZoomStart(
|
||||
Offset location, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(!isPanZoomActive);
|
||||
assert(kind == PointerDeviceKind.trackpad);
|
||||
_location = location;
|
||||
_pan = Offset.zero;
|
||||
_isPanZoomActive = true;
|
||||
return PointerPanZoomStartEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
device: _device,
|
||||
pointer: pointer,
|
||||
@ -351,6 +392,7 @@ class TestPointer {
|
||||
double scale = 1,
|
||||
double rotation = 0,
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) {
|
||||
assert(isPanZoomActive);
|
||||
assert(kind == PointerDeviceKind.trackpad);
|
||||
@ -358,6 +400,7 @@ class TestPointer {
|
||||
final Offset panDelta = pan - _pan!;
|
||||
_pan = pan;
|
||||
return PointerPanZoomUpdateEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
device: _device,
|
||||
pointer: pointer,
|
||||
@ -374,12 +417,13 @@ class TestPointer {
|
||||
///
|
||||
/// By default, the time stamp on the event is [Duration.zero]. You can give a
|
||||
/// specific time stamp by passing the `timeStamp` argument.
|
||||
PointerPanZoomEndEvent panZoomEnd({Duration timeStamp = Duration.zero}) {
|
||||
PointerPanZoomEndEvent panZoomEnd({Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(isPanZoomActive);
|
||||
assert(kind == PointerDeviceKind.trackpad);
|
||||
_isPanZoomActive = false;
|
||||
_pan = null;
|
||||
return PointerPanZoomEndEvent(
|
||||
viewId: view?.viewId ?? WidgetsBinding.instance.platformDispatcher.implicitView!.viewId,
|
||||
timeStamp: timeStamp,
|
||||
device: _device,
|
||||
pointer: pointer,
|
||||
@ -428,13 +472,17 @@ class TestGesture {
|
||||
|
||||
/// Dispatch a pointer down event at the given `downLocation`, caching the
|
||||
/// hit test result.
|
||||
Future<void> down(Offset downLocation, {Duration timeStamp = Duration.zero}) async {
|
||||
Future<void> down(
|
||||
Offset downLocation, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) async {
|
||||
assert(
|
||||
_pointer.kind != PointerDeviceKind.trackpad,
|
||||
'Trackpads are expected to send panZoomStart events, not down events.',
|
||||
);
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
return _dispatcher(_pointer.down(downLocation, timeStamp: timeStamp));
|
||||
return _dispatcher(_pointer.down(downLocation, timeStamp: timeStamp, view: view));
|
||||
});
|
||||
}
|
||||
|
||||
@ -491,16 +539,17 @@ class TestGesture {
|
||||
/// * [WidgetController.timedDrag], a method to simulate the drag of a given widget in a given duration.
|
||||
/// It sends move events at a given frequency and it is useful when there are listeners involved.
|
||||
/// * [WidgetController.fling], a method to simulate a fling.
|
||||
Future<void> moveBy(Offset offset, {Duration timeStamp = Duration.zero}) {
|
||||
Future<void> moveBy(Offset offset, {Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(_pointer.location != null);
|
||||
if (_pointer.isPanZoomActive) {
|
||||
return panZoomUpdate(
|
||||
_pointer.location!,
|
||||
pan: (_pointer.pan ?? Offset.zero) + offset,
|
||||
timeStamp: timeStamp,
|
||||
view: view,
|
||||
);
|
||||
} else {
|
||||
return moveTo(_pointer.location! + offset, timeStamp: timeStamp);
|
||||
return moveTo(_pointer.location! + offset, timeStamp: timeStamp, view: view);
|
||||
}
|
||||
}
|
||||
|
||||
@ -514,28 +563,28 @@ class TestGesture {
|
||||
/// * [WidgetController.timedDrag], a method to simulate the drag of a given widget in a given duration.
|
||||
/// It sends move events at a given frequency and it is useful when there are listeners involved.
|
||||
/// * [WidgetController.fling], a method to simulate a fling.
|
||||
Future<void> moveTo(Offset location, {Duration timeStamp = Duration.zero}) {
|
||||
Future<void> moveTo(Offset location, {Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
assert(_pointer.kind != PointerDeviceKind.trackpad);
|
||||
return TestAsyncUtils.guard<void>(() {
|
||||
if (_pointer._isDown) {
|
||||
return _dispatcher(_pointer.move(location, timeStamp: timeStamp));
|
||||
return _dispatcher(_pointer.move(location, timeStamp: timeStamp, view: view));
|
||||
} else {
|
||||
return _dispatcher(_pointer.hover(location, timeStamp: timeStamp));
|
||||
return _dispatcher(_pointer.hover(location, timeStamp: timeStamp, view: view));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// End the gesture by releasing the pointer. For trackpad pointers this
|
||||
/// will send a panZoomEnd event instead of an up event.
|
||||
Future<void> up({Duration timeStamp = Duration.zero}) {
|
||||
Future<void> up({Duration timeStamp = Duration.zero, FlutterView? view}) {
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
if (_pointer.kind == PointerDeviceKind.trackpad) {
|
||||
assert(_pointer._isPanZoomActive);
|
||||
await _dispatcher(_pointer.panZoomEnd(timeStamp: timeStamp));
|
||||
await _dispatcher(_pointer.panZoomEnd(timeStamp: timeStamp, view: view));
|
||||
assert(!_pointer._isPanZoomActive);
|
||||
} else {
|
||||
assert(_pointer._isDown);
|
||||
await _dispatcher(_pointer.up(timeStamp: timeStamp));
|
||||
await _dispatcher(_pointer.up(timeStamp: timeStamp, view: view));
|
||||
assert(!_pointer._isDown);
|
||||
}
|
||||
});
|
||||
@ -555,13 +604,17 @@ class TestGesture {
|
||||
|
||||
/// Dispatch a pointer pan zoom start event at the given `location`, caching the
|
||||
/// hit test result.
|
||||
Future<void> panZoomStart(Offset location, {Duration timeStamp = Duration.zero}) async {
|
||||
Future<void> panZoomStart(
|
||||
Offset location, {
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) async {
|
||||
assert(
|
||||
_pointer.kind == PointerDeviceKind.trackpad,
|
||||
'Only trackpads can send PointerPanZoom events.',
|
||||
);
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
return _dispatcher(_pointer.panZoomStart(location, timeStamp: timeStamp));
|
||||
return _dispatcher(_pointer.panZoomStart(location, timeStamp: timeStamp, view: view));
|
||||
});
|
||||
}
|
||||
|
||||
@ -573,6 +626,7 @@ class TestGesture {
|
||||
double scale = 1,
|
||||
double rotation = 0,
|
||||
Duration timeStamp = Duration.zero,
|
||||
FlutterView? view,
|
||||
}) async {
|
||||
assert(
|
||||
_pointer.kind == PointerDeviceKind.trackpad,
|
||||
@ -586,6 +640,7 @@ class TestGesture {
|
||||
scale: scale,
|
||||
rotation: rotation,
|
||||
timeStamp: timeStamp,
|
||||
view: view,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user