Skip to content

Commit 3ac8b26

Browse files
authored
✨ Introduces PositionedGestureDetails (flutter#160714)
Resolves flutter#101530 `PositionedGestureDetails` is an abstract interface that is meant to contain positions for pointer events. ## 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. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
1 parent eea3fdf commit 3ac8b26

10 files changed

Lines changed: 559 additions & 198 deletions

File tree

‎packages/flutter/lib/gestures.dart‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export 'src/gestures/drag_details.dart';
1717
export 'src/gestures/eager.dart';
1818
export 'src/gestures/events.dart';
1919
export 'src/gestures/force_press.dart';
20+
export 'src/gestures/gesture_details.dart';
2021
export 'src/gestures/gesture_settings.dart';
2122
export 'src/gestures/hit_test.dart';
2223
export 'src/gestures/long_press.dart';

‎packages/flutter/lib/src/gestures/drag_details.dart‎

Lines changed: 65 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ library;
77

88
import 'package:flutter/foundation.dart';
99

10+
import 'gesture_details.dart';
1011
import 'velocity_tracker.dart';
1112

1213
export 'dart:ui' show Offset, PointerDeviceKind;
@@ -21,29 +22,25 @@ export 'velocity_tracker.dart' show Velocity;
2122
/// * [DragStartDetails], the details for [GestureDragStartCallback].
2223
/// * [DragUpdateDetails], the details for [GestureDragUpdateCallback].
2324
/// * [DragEndDetails], the details for [GestureDragEndCallback].
24-
class DragDownDetails {
25+
class DragDownDetails with Diagnosticable implements PositionedGestureDetails {
2526
/// Creates details for a [GestureDragDownCallback].
2627
DragDownDetails({this.globalPosition = Offset.zero, Offset? localPosition})
2728
: localPosition = localPosition ?? globalPosition;
2829

29-
/// The global position at which the pointer contacted the screen.
30-
///
31-
/// Defaults to the origin if not specified in the constructor.
32-
///
33-
/// See also:
34-
///
35-
/// * [localPosition], which is the [globalPosition] transformed to the
36-
/// coordinate space of the event receiver.
30+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
31+
@override
3732
final Offset globalPosition;
3833

39-
/// The local position in the coordinate system of the event receiver at
40-
/// which the pointer contacted the screen.
41-
///
42-
/// Defaults to [globalPosition] if not specified in the constructor.
34+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
35+
@override
4336
final Offset localPosition;
4437

4538
@override
46-
String toString() => '${objectRuntimeType(this, 'DragDownDetails')}($globalPosition)';
39+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
40+
super.debugFillProperties(properties);
41+
properties.add(DiagnosticsProperty<Offset>('globalPosition', globalPosition));
42+
properties.add(DiagnosticsProperty<Offset>('localPosition', localPosition));
43+
}
4744
}
4845

4946
/// Signature for when a pointer has contacted the screen and might begin to
@@ -62,46 +59,40 @@ typedef GestureDragDownCallback = void Function(DragDownDetails details);
6259
/// * [DragDownDetails], the details for [GestureDragDownCallback].
6360
/// * [DragUpdateDetails], the details for [GestureDragUpdateCallback].
6461
/// * [DragEndDetails], the details for [GestureDragEndCallback].
65-
class DragStartDetails {
62+
class DragStartDetails with Diagnosticable implements PositionedGestureDetails {
6663
/// Creates details for a [GestureDragStartCallback].
6764
DragStartDetails({
68-
this.sourceTimeStamp,
6965
this.globalPosition = Offset.zero,
7066
Offset? localPosition,
67+
this.sourceTimeStamp,
7168
this.kind,
7269
}) : localPosition = localPosition ?? globalPosition;
7370

71+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
72+
@override
73+
final Offset globalPosition;
74+
75+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
76+
@override
77+
final Offset localPosition;
78+
7479
/// Recorded timestamp of the source pointer event that triggered the drag
7580
/// event.
7681
///
7782
/// Could be null if triggered from proxied events such as accessibility.
7883
final Duration? sourceTimeStamp;
7984

80-
/// The global position at which the pointer contacted the screen.
81-
///
82-
/// Defaults to the origin if not specified in the constructor.
83-
///
84-
/// See also:
85-
///
86-
/// * [localPosition], which is the [globalPosition] transformed to the
87-
/// coordinate space of the event receiver.
88-
final Offset globalPosition;
89-
90-
/// The local position in the coordinate system of the event receiver at
91-
/// which the pointer contacted the screen.
92-
///
93-
/// Defaults to [globalPosition] if not specified in the constructor.
94-
final Offset localPosition;
95-
9685
/// The kind of the device that initiated the event.
9786
final PointerDeviceKind? kind;
9887

99-
// TODO(ianh): Expose the current position, so that you can have a no-jump
100-
// drag even when disambiguating (though of course it would lag the finger
101-
// instead).
102-
10388
@override
104-
String toString() => '${objectRuntimeType(this, 'DragStartDetails')}($globalPosition)';
89+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
90+
super.debugFillProperties(properties);
91+
properties.add(DiagnosticsProperty<Offset>('globalPosition', globalPosition));
92+
properties.add(DiagnosticsProperty<Offset>('localPosition', localPosition));
93+
properties.add(DiagnosticsProperty<Duration?>('sourceTimeStamp', sourceTimeStamp));
94+
properties.add(EnumProperty<PointerDeviceKind?>('kind', kind));
95+
}
10596
}
10697

10798
/// {@template flutter.gestures.dragdetails.GestureDragStartCallback}
@@ -122,24 +113,32 @@ typedef GestureDragStartCallback = void Function(DragStartDetails details);
122113
/// * [DragDownDetails], the details for [GestureDragDownCallback].
123114
/// * [DragStartDetails], the details for [GestureDragStartCallback].
124115
/// * [DragEndDetails], the details for [GestureDragEndCallback].
125-
class DragUpdateDetails {
116+
class DragUpdateDetails with Diagnosticable implements PositionedGestureDetails {
126117
/// Creates details for a [GestureDragUpdateCallback].
127118
///
128119
/// If [primaryDelta] is non-null, then its value must match one of the
129120
/// coordinates of [delta] and the other coordinate must be zero.
130121
DragUpdateDetails({
122+
required this.globalPosition,
123+
Offset? localPosition,
131124
this.sourceTimeStamp,
132125
this.delta = Offset.zero,
133126
this.primaryDelta,
134-
required this.globalPosition,
135-
Offset? localPosition,
136127
}) : assert(
137128
primaryDelta == null ||
138129
(primaryDelta == delta.dx && delta.dy == 0.0) ||
139130
(primaryDelta == delta.dy && delta.dx == 0.0),
140131
),
141132
localPosition = localPosition ?? globalPosition;
142133

134+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
135+
@override
136+
final Offset globalPosition;
137+
138+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
139+
@override
140+
final Offset localPosition;
141+
143142
/// Recorded timestamp of the source pointer event that triggered the drag
144143
/// event.
145144
///
@@ -169,22 +168,15 @@ class DragUpdateDetails {
169168
/// Defaults to null if not specified in the constructor.
170169
final double? primaryDelta;
171170

172-
/// The pointer's global position when it triggered this update.
173-
///
174-
/// See also:
175-
///
176-
/// * [localPosition], which is the [globalPosition] transformed to the
177-
/// coordinate space of the event receiver.
178-
final Offset globalPosition;
179-
180-
/// The local position in the coordinate system of the event receiver at
181-
/// which the pointer contacted the screen.
182-
///
183-
/// Defaults to [globalPosition] if not specified in the constructor.
184-
final Offset localPosition;
185-
186171
@override
187-
String toString() => '${objectRuntimeType(this, 'DragUpdateDetails')}($delta)';
172+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
173+
super.debugFillProperties(properties);
174+
properties.add(DiagnosticsProperty<Offset>('globalPosition', globalPosition));
175+
properties.add(DiagnosticsProperty<Offset>('localPosition', localPosition));
176+
properties.add(DiagnosticsProperty<Duration?>('sourceTimeStamp', sourceTimeStamp));
177+
properties.add(DiagnosticsProperty<Offset>('delta', delta));
178+
properties.add(DoubleProperty('primaryDelta', primaryDelta));
179+
}
188180
}
189181

190182
/// {@template flutter.gestures.dragdetails.GestureDragUpdateCallback}
@@ -206,24 +198,32 @@ typedef GestureDragUpdateCallback = void Function(DragUpdateDetails details);
206198
/// * [DragDownDetails], the details for [GestureDragDownCallback].
207199
/// * [DragStartDetails], the details for [GestureDragStartCallback].
208200
/// * [DragUpdateDetails], the details for [GestureDragUpdateCallback].
209-
class DragEndDetails {
201+
class DragEndDetails with Diagnosticable implements PositionedGestureDetails {
210202
/// Creates details for a [GestureDragEndCallback].
211203
///
212204
/// If [primaryVelocity] is non-null, its value must match one of the
213205
/// coordinates of `velocity.pixelsPerSecond` and the other coordinate
214206
/// must be zero.
215207
DragEndDetails({
216-
this.velocity = Velocity.zero,
217-
this.primaryVelocity,
218208
this.globalPosition = Offset.zero,
219209
Offset? localPosition,
210+
this.velocity = Velocity.zero,
211+
this.primaryVelocity,
220212
}) : assert(
221213
primaryVelocity == null ||
222214
(primaryVelocity == velocity.pixelsPerSecond.dx && velocity.pixelsPerSecond.dy == 0) ||
223215
(primaryVelocity == velocity.pixelsPerSecond.dy && velocity.pixelsPerSecond.dx == 0),
224216
),
225217
localPosition = localPosition ?? globalPosition;
226218

219+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
220+
@override
221+
final Offset globalPosition;
222+
223+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
224+
@override
225+
final Offset localPosition;
226+
227227
/// The velocity the pointer was moving when it stopped contacting the screen.
228228
///
229229
/// Defaults to zero if not specified in the constructor.
@@ -241,23 +241,12 @@ class DragEndDetails {
241241
/// Defaults to null if not specified in the constructor.
242242
final double? primaryVelocity;
243243

244-
/// The global position the pointer is located at when the drag
245-
/// gesture has been completed.
246-
///
247-
/// Defaults to the origin if not specified in the constructor.
248-
///
249-
/// See also:
250-
///
251-
/// * [localPosition], which is the [globalPosition] transformed to the
252-
/// coordinate space of the event receiver.
253-
final Offset globalPosition;
254-
255-
/// The local position in the coordinate system of the event receiver when
256-
/// the drag gesture has been completed.
257-
///
258-
/// Defaults to [globalPosition] if not specified in the constructor.
259-
final Offset localPosition;
260-
261244
@override
262-
String toString() => '${objectRuntimeType(this, 'DragEndDetails')}($velocity)';
245+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
246+
super.debugFillProperties(properties);
247+
properties.add(DiagnosticsProperty<Offset>('globalPosition', globalPosition));
248+
properties.add(DiagnosticsProperty<Offset>('localPosition', localPosition));
249+
properties.add(DiagnosticsProperty<Velocity>('velocity', velocity));
250+
properties.add(DoubleProperty('primaryVelocity', primaryVelocity));
251+
}
263252
}

‎packages/flutter/lib/src/gestures/force_press.dart‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5-
import 'package:flutter/foundation.dart' show clampDouble;
5+
import 'package:flutter/foundation.dart';
66

77
import 'events.dart';
8+
import 'gesture_details.dart';
89
import 'recognizer.dart';
910

1011
export 'dart:ui' show Offset, PointerDeviceKind;
@@ -43,20 +44,30 @@ enum _ForceState {
4344
/// * [ForcePressGestureRecognizer.onStart], [ForcePressGestureRecognizer.onPeak],
4445
/// [ForcePressGestureRecognizer.onEnd], and [ForcePressGestureRecognizer.onUpdate]
4546
/// which use [ForcePressDetails].
46-
class ForcePressDetails {
47+
class ForcePressDetails with Diagnosticable implements PositionedGestureDetails {
4748
/// Creates details for a [GestureForcePressStartCallback],
4849
/// [GestureForcePressPeakCallback] or [GestureForcePressEndCallback].
4950
ForcePressDetails({required this.globalPosition, Offset? localPosition, required this.pressure})
5051
: localPosition = localPosition ?? globalPosition;
5152

52-
/// The global position at which the function was called.
53+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
54+
@override
5355
final Offset globalPosition;
5456

55-
/// The local position at which the function was called.
57+
/// {@macro flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
58+
@override
5659
final Offset localPosition;
5760

5861
/// The pressure of the pointer on the screen.
5962
final double pressure;
63+
64+
@override
65+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
66+
super.debugFillProperties(properties);
67+
properties.add(DiagnosticsProperty<Offset>('globalPosition', globalPosition));
68+
properties.add(DiagnosticsProperty<Offset>('localPosition', localPosition));
69+
properties.add(DoubleProperty('pressure', pressure));
70+
}
6071
}
6172

6273
/// Signature used by a [ForcePressGestureRecognizer] for when a pointer has
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ui' show Offset;
6+
7+
/// An abstract interface representing gesture details that include positional information.
8+
///
9+
/// This class serve as a common interface for gesture details that involve positional data,
10+
/// such as dragging and tapping. It simplifies gesture handling by enabling the use of shared logic
11+
/// across multiple gesture types, users can create a method to handle a single gesture details
12+
/// with this position information. For example:
13+
///
14+
/// ```dart
15+
/// void handlePositionedGestures(PositionedGestureDetails details) {
16+
/// // Handle the positional information of the gesture details.
17+
/// }
18+
/// ```
19+
abstract interface class PositionedGestureDetails {
20+
/// Creates details with positions.
21+
const PositionedGestureDetails({required this.globalPosition, required this.localPosition});
22+
23+
/// {@template flutter.gestures.gesturedetails.PositionedGestureDetails.globalPosition}
24+
/// The global position at which the pointer interacts with the screen.
25+
///
26+
/// See also:
27+
///
28+
/// * [localPosition], which is the [globalPosition] transformed to the
29+
/// coordinate space of the event receiver.
30+
/// {@endtemplate}
31+
final Offset globalPosition;
32+
33+
/// {@template flutter.gestures.gesturedetails.PositionedGestureDetails.localPosition}
34+
/// The local position in the coordinate system of the event receiver at
35+
/// which the pointer interacts with the screen.
36+
///
37+
/// See also:
38+
///
39+
/// * [globalPosition], which is the global position at which the pointer
40+
/// interacts with the screen.
41+
/// {@endtemplate}
42+
final Offset localPosition;
43+
}

0 commit comments

Comments
 (0)