Draggable feedback positioning (#145647)
Fixes a calculation in Draggable that was previously wrong when the target was transformed.
This commit is contained in:
parent
b974dcb490
commit
5f9e069111
@ -833,6 +833,7 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
|
final List<_DragTargetState<Object>> _enteredTargets = <_DragTargetState<Object>>[];
|
||||||
Offset _position;
|
Offset _position;
|
||||||
Offset? _lastOffset;
|
Offset? _lastOffset;
|
||||||
|
late Offset _overlayOffset;
|
||||||
OverlayEntry? _entry;
|
OverlayEntry? _entry;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -858,6 +859,10 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
|
|
||||||
void updateDrag(Offset globalPosition) {
|
void updateDrag(Offset globalPosition) {
|
||||||
_lastOffset = globalPosition - dragStartPoint;
|
_lastOffset = globalPosition - dragStartPoint;
|
||||||
|
final RenderBox box = overlayState.context.findRenderObject()! as RenderBox;
|
||||||
|
final Offset overlaySpaceOffset = box.globalToLocal(globalPosition);
|
||||||
|
_overlayOffset = overlaySpaceOffset - dragStartPoint;
|
||||||
|
|
||||||
_entry!.markNeedsBuild();
|
_entry!.markNeedsBuild();
|
||||||
final HitTestResult result = HitTestResult();
|
final HitTestResult result = HitTestResult();
|
||||||
WidgetsBinding.instance.hitTestInView(result, globalPosition + feedbackOffset, viewId);
|
WidgetsBinding.instance.hitTestInView(result, globalPosition + feedbackOffset, viewId);
|
||||||
@ -943,11 +948,9 @@ class _DragAvatar<T extends Object> extends Drag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _build(BuildContext context) {
|
Widget _build(BuildContext context) {
|
||||||
final RenderBox box = overlayState.context.findRenderObject()! as RenderBox;
|
|
||||||
final Offset overlayTopLeft = box.localToGlobal(Offset.zero);
|
|
||||||
return Positioned(
|
return Positioned(
|
||||||
left: _lastOffset!.dx - overlayTopLeft.dx,
|
left: _overlayOffset.dx,
|
||||||
top: _lastOffset!.dy - overlayTopLeft.dy,
|
top: _overlayOffset.dy,
|
||||||
child: ExcludeSemantics(
|
child: ExcludeSemantics(
|
||||||
excluding: ignoringFeedbackSemantics,
|
excluding: ignoringFeedbackSemantics,
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
|
@ -967,6 +967,10 @@ void main() {
|
|||||||
await gesture.moveTo(thirdLocation);
|
await gesture.moveTo(thirdLocation);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getTopLeft(find.text('N')), thirdLocation);
|
expect(tester.getTopLeft(find.text('N')), thirdLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Horizontal axis draggable moves horizontally', (WidgetTester tester) async {
|
testWidgets('Horizontal axis draggable moves horizontally', (WidgetTester tester) async {
|
||||||
@ -982,6 +986,10 @@ void main() {
|
|||||||
await gesture.moveTo(thirdLocation);
|
await gesture.moveTo(thirdLocation);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getTopLeft(find.text('H')), thirdLocation);
|
expect(tester.getTopLeft(find.text('H')), thirdLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Horizontal axis draggable does not move vertically', (WidgetTester tester) async {
|
testWidgets('Horizontal axis draggable does not move vertically', (WidgetTester tester) async {
|
||||||
@ -1000,6 +1008,10 @@ void main() {
|
|||||||
await gesture.moveTo(thirdDragLocation);
|
await gesture.moveTo(thirdDragLocation);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getTopLeft(find.text('H')), thirdWidgetLocation);
|
expect(tester.getTopLeft(find.text('H')), thirdWidgetLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Vertical axis draggable moves vertically', (WidgetTester tester) async {
|
testWidgets('Vertical axis draggable moves vertically', (WidgetTester tester) async {
|
||||||
@ -1015,6 +1027,10 @@ void main() {
|
|||||||
await gesture.moveTo(thirdLocation);
|
await gesture.moveTo(thirdLocation);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getTopLeft(find.text('V')), thirdLocation);
|
expect(tester.getTopLeft(find.text('V')), thirdLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Vertical axis draggable does not move horizontally', (WidgetTester tester) async {
|
testWidgets('Vertical axis draggable does not move horizontally', (WidgetTester tester) async {
|
||||||
@ -1033,6 +1049,10 @@ void main() {
|
|||||||
await gesture.moveTo(thirdDragLocation);
|
await gesture.moveTo(thirdDragLocation);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
expect(tester.getTopLeft(find.text('V')), thirdWidgetLocation);
|
expect(tester.getTopLeft(find.text('V')), thirdWidgetLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1666,6 +1686,10 @@ void main() {
|
|||||||
expect(find.text('Dragging'), findsOneWidget);
|
expect(find.text('Dragging'), findsOneWidget);
|
||||||
expect(find.text('Target'), findsOneWidget);
|
expect(find.text('Target'), findsOneWidget);
|
||||||
expect(find.text('Rejected'), findsNothing);
|
expect(find.text('Rejected'), findsNothing);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -3099,6 +3123,10 @@ void main() {
|
|||||||
),
|
),
|
||||||
findsNothing,
|
findsNothing,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Drag feedback is put on root overlay with [rootOverlay] flag', (WidgetTester tester) async {
|
testWidgets('Drag feedback is put on root overlay with [rootOverlay] flag', (WidgetTester tester) async {
|
||||||
@ -3497,6 +3525,93 @@ void main() {
|
|||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('Drag and drop - feedback matches pointer in scaled MaterialApp', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(Transform.scale(
|
||||||
|
scale: 0.5,
|
||||||
|
child: const MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Draggable<int>(
|
||||||
|
data: 42,
|
||||||
|
feedback: Text('Feedback'),
|
||||||
|
child: Text('Source'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final Offset location = tester.getTopLeft(find.text('Source'));
|
||||||
|
final TestGesture gesture = await tester.startGesture(location);
|
||||||
|
final Offset secondLocation = location + const Offset(100, 100);
|
||||||
|
await gesture.moveTo(secondLocation);
|
||||||
|
await tester.pump();
|
||||||
|
final Offset appTopLeft = tester.getTopLeft(find.byType(MaterialApp));
|
||||||
|
expect(tester.getTopLeft(find.text('Source')), appTopLeft);
|
||||||
|
expect(tester.getTopLeft(find.text('Feedback')), secondLocation);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Drag and drop - childDragAnchorStrategy works in scaled MaterialApp', (WidgetTester tester) async {
|
||||||
|
final Key sourceKey = UniqueKey();
|
||||||
|
final Key feedbackKey = UniqueKey();
|
||||||
|
await tester.pumpWidget(Transform.scale(
|
||||||
|
scale: 0.5,
|
||||||
|
child: MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Draggable<int>(
|
||||||
|
data: 42,
|
||||||
|
feedback: Text('Text', key: feedbackKey),
|
||||||
|
child: Text('Text', key: sourceKey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
final Finder source = find.byKey(sourceKey);
|
||||||
|
final Finder feedback = find.byKey(feedbackKey);
|
||||||
|
|
||||||
|
final TestGesture gesture = await tester.startGesture(tester.getCenter(source));
|
||||||
|
await tester.pump();
|
||||||
|
expect(tester.getTopLeft(source), tester.getTopLeft(feedback));
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('Drag and drop - feedback matches pointer in rotated MaterialApp', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(Transform.rotate(
|
||||||
|
angle: 1, // ~57 degrees
|
||||||
|
child: const MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
body: Draggable<int>(
|
||||||
|
data: 42,
|
||||||
|
feedback: Text('Feedback'),
|
||||||
|
child: Text('Source'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
final Offset location = tester.getTopLeft(find.text('Source'));
|
||||||
|
final TestGesture gesture = await tester.startGesture(location);
|
||||||
|
final Offset secondLocation = location + const Offset(100, 100);
|
||||||
|
await gesture.moveTo(secondLocation);
|
||||||
|
await tester.pump();
|
||||||
|
final Offset appTopLeft = tester.getTopLeft(find.byType(MaterialApp));
|
||||||
|
expect(tester.getTopLeft(find.text('Source')), appTopLeft);
|
||||||
|
final Offset feedbackTopLeft = tester.getTopLeft(find.text('Feedback'));
|
||||||
|
|
||||||
|
// Different rotations can incur rounding errors, this makes it more robust
|
||||||
|
expect(feedbackTopLeft.dx, moreOrLessEquals(secondLocation.dx));
|
||||||
|
expect(feedbackTopLeft.dy, moreOrLessEquals(secondLocation.dy));
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('configurable Draggable hit test behavior', (WidgetTester tester) async {
|
testWidgets('configurable Draggable hit test behavior', (WidgetTester tester) async {
|
||||||
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
|
const HitTestBehavior hitTestBehavior = HitTestBehavior.deferToChild;
|
||||||
|
|
||||||
@ -3573,6 +3688,10 @@ void main() {
|
|||||||
|
|
||||||
await tester.tap(find.text('Draggable'));
|
await tester.tap(find.text('Draggable'));
|
||||||
expect(onTap, true);
|
expect(onTap, true);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async {
|
testWidgets('configurable feedback ignore pointer behavior - LongPressDraggable', (WidgetTester tester) async {
|
||||||
@ -3604,6 +3723,10 @@ void main() {
|
|||||||
|
|
||||||
await tester.tap(find.text('Draggable'));
|
await tester.tap(find.text('Draggable'));
|
||||||
expect(onTap, true);
|
expect(onTap, true);
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async {
|
testWidgets('configurable DragTarget hit test behavior', (WidgetTester tester) async {
|
||||||
@ -3811,6 +3934,10 @@ Future<void> _testChildAnchorFeedbackPosition({ required WidgetTester tester, do
|
|||||||
final Offset sourceTopLeft = tester.getTopLeft(find.text('Source'));
|
final Offset sourceTopLeft = tester.getTopLeft(find.text('Source'));
|
||||||
final Offset dragOffset = secondLocation - firstLocation;
|
final Offset dragOffset = secondLocation - firstLocation;
|
||||||
expect(feedbackTopLeft, equals(sourceTopLeft + dragOffset));
|
expect(feedbackTopLeft, equals(sourceTopLeft + dragOffset));
|
||||||
|
|
||||||
|
// Finish gesture to release resources.
|
||||||
|
await gesture.up();
|
||||||
|
await tester.pump();
|
||||||
}
|
}
|
||||||
|
|
||||||
class DragTargetData { }
|
class DragTargetData { }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user