Skip to content

Commit 129e51b

Browse files
JaffaKetchupQuirillefreekvandeven
authored
feat: added options to customize double-tap (drag) zoom gestures (#2070)
Co-authored-by: Kiril Tijsma <[email protected]> Co-authored-by: Freek van de Ven <[email protected]>
1 parent c428d6e commit 129e51b

File tree

3 files changed

+58
-15
lines changed

3 files changed

+58
-15
lines changed

example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
flutter:
1212
sdk: flutter
1313
flutter_map:
14-
flutter_map_cancellable_tile_provider: ^3.0.2
14+
flutter_map_cancellable_tile_provider: ^3.1.0
1515
flutter_web_plugins:
1616
sdk: flutter
1717
http: ^1.2.2

lib/src/gestures/map_interactive_viewer.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ class MapInteractiveViewer extends StatefulWidget {
5353
class MapInteractiveViewerState extends State<MapInteractiveViewer>
5454
with TickerProviderStateMixin {
5555
static const int _kMinFlingVelocity = 800;
56-
static const _kDoubleTapZoomDuration = 200;
5756

5857
/// The maximum delay between to taps to be counted as a double tap.
5958
static const doubleTapDelay = Duration(milliseconds: 250);
@@ -84,15 +83,12 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
8483
late Offset _focalStartLocal;
8584
late LatLng _focalStartLatLng;
8685

87-
late final AnimationController _flingController =
88-
AnimationController(vsync: this);
86+
late final _flingController = AnimationController(vsync: this);
8987
late Animation<Offset> _flingAnimation;
9088

91-
late final AnimationController _doubleTapController = AnimationController(
89+
late final _doubleTapController = AnimationController(
9290
vsync: this,
93-
duration: const Duration(
94-
milliseconds: _kDoubleTapZoomDuration,
95-
),
91+
duration: _interactionOptions.doubleTapZoomDuration,
9692
);
9793
late Animation<double> _doubleTapZoomAnimation;
9894
late Animation<LatLng> _doubleTapCenterAnimation;
@@ -876,11 +872,11 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
876872

877873
void _startDoubleTapAnimation(double newZoom, LatLng newCenter) {
878874
_doubleTapZoomAnimation = Tween<double>(begin: _camera.zoom, end: newZoom)
879-
.chain(CurveTween(curve: Curves.linear))
875+
.chain(CurveTween(curve: _interactionOptions.doubleTapZoomCurve))
880876
.animate(_doubleTapController);
881877
_doubleTapCenterAnimation =
882878
LatLngTween(begin: _camera.center, end: newCenter)
883-
.chain(CurveTween(curve: Curves.linear))
879+
.chain(CurveTween(curve: _interactionOptions.doubleTapZoomCurve))
884880
.animate(_doubleTapController);
885881
_doubleTapController.forward(from: 0);
886882
}
@@ -923,7 +919,11 @@ class MapInteractiveViewerState extends State<MapInteractiveViewer>
923919
final flags = _interactionOptions.flags;
924920
if (InteractiveFlag.hasDoubleTapDragZoom(flags)) {
925921
final verticalOffset = (_focalStartLocal - details.localFocalPoint).dy;
926-
final newZoom = _mapZoomStart - verticalOffset / 360 * _camera.zoom;
922+
final newZoom = _mapZoomStart -
923+
_interactionOptions.doubleTapDragZoomChangeCalculator(
924+
verticalOffset,
925+
_camera,
926+
);
927927

928928
final min = _options.minZoom ?? 0.0;
929929
final max = _options.maxZoom ?? double.infinity;

lib/src/map/options/interaction.dart

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
import 'package:flutter/animation.dart';
12
import 'package:flutter_map/flutter_map.dart';
23
import 'package:meta/meta.dart';
34

45
/// All interactive options for [FlutterMap]
56
@immutable
6-
final class InteractionOptions {
7+
class InteractionOptions {
78
/// See [InteractiveFlag] for custom settings
89
final int flags;
910

@@ -66,6 +67,27 @@ final class InteractionOptions {
6667
/// with the scroll wheel of a mouse.
6768
final double scrollWheelVelocity;
6869

70+
/// Calculates the zoom difference to apply to the initial zoom level when a
71+
/// user is performing a double-tap drag zoom gesture
72+
///
73+
/// `verticalOffset` is the vertical distance between the user's initial
74+
/// pointer-down position and their current dragged position. `camera` may be
75+
/// used, for example, to factor in the current zoom level.
76+
///
77+
/// The default calculator is [defaultDoubleTapDragZoomChangeCalculator].
78+
final double Function(double verticalOffset, MapCamera camera)
79+
doubleTapDragZoomChangeCalculator;
80+
81+
/// The duration of the animation played when double-tap zooming
82+
///
83+
/// Defaults to 200ms.
84+
final Duration doubleTapZoomDuration;
85+
86+
/// The curve of the animation played when double-tap zooming
87+
///
88+
/// Defaults to [Curves.fastOutSlowIn].
89+
final Curve doubleTapZoomCurve;
90+
6991
/// Options to configure cursor/keyboard rotation
7092
///
7193
/// Cursor/keyboard rotation is designed for desktop platforms, and allows the
@@ -103,21 +125,35 @@ final class InteractionOptions {
103125
this.pinchMoveWinGestures =
104126
MultiFingerGesture.pinchZoom | MultiFingerGesture.pinchMove,
105127
this.scrollWheelVelocity = 0.005,
128+
this.doubleTapDragZoomChangeCalculator =
129+
defaultDoubleTapDragZoomChangeCalculator,
130+
this.doubleTapZoomDuration = const Duration(milliseconds: 200),
131+
this.doubleTapZoomCurve = Curves.fastOutSlowIn,
106132
this.cursorKeyboardRotationOptions = const CursorKeyboardRotationOptions(),
107133
this.keyboardOptions = const KeyboardOptions(),
108134
}) : assert(
109135
rotationThreshold >= 0.0,
110-
'rotationThreshold needs to be a positive value',
136+
'`rotationThreshold` must be positive',
111137
),
112138
assert(
113139
pinchZoomThreshold >= 0.0,
114-
'pinchZoomThreshold needs to be a positive value',
140+
'`pinchZoomThreshold` must be positive',
115141
),
116142
assert(
117143
pinchMoveThreshold >= 0.0,
118-
'pinchMoveThreshold needs to be a positive value',
144+
'`pinchMoveThreshold` must be positive',
119145
);
120146

147+
/// Default calculator function for [doubleTapDragZoomChangeCalculator]
148+
///
149+
/// Uses a constant of 1/360, and changes the zoom speed based on the current
150+
/// zoom level.
151+
static double defaultDoubleTapDragZoomChangeCalculator(
152+
double verticalOffset,
153+
MapCamera camera,
154+
) =>
155+
(1 / 360) * camera.zoom * verticalOffset;
156+
121157
@override
122158
bool operator ==(Object other) =>
123159
other is InteractionOptions &&
@@ -131,6 +167,10 @@ final class InteractionOptions {
131167
pinchMoveThreshold == other.pinchMoveThreshold &&
132168
pinchMoveWinGestures == other.pinchMoveWinGestures &&
133169
scrollWheelVelocity == other.scrollWheelVelocity &&
170+
doubleTapDragZoomChangeCalculator ==
171+
other.doubleTapDragZoomChangeCalculator &&
172+
doubleTapZoomDuration == other.doubleTapZoomDuration &&
173+
doubleTapZoomCurve == other.doubleTapZoomCurve &&
134174
keyboardOptions == other.keyboardOptions;
135175

136176
@override
@@ -145,6 +185,9 @@ final class InteractionOptions {
145185
pinchMoveThreshold,
146186
pinchMoveWinGestures,
147187
scrollWheelVelocity,
188+
doubleTapDragZoomChangeCalculator,
189+
doubleTapZoomDuration,
190+
doubleTapZoomCurve,
148191
keyboardOptions,
149192
);
150193
}

0 commit comments

Comments
 (0)