Skip to content

Commit 1477eab

Browse files
authored
Added InteractiveFlag.doubleTapDragZoom (#1603)
* Added `InteractiveFlag.doubleTapDragZoom` Improved example app's Interactive Flags page Bumped version to match latest on pub.dev * Syntactic improvements to example app's Interactive Flags page
1 parent 9907251 commit 1477eab

File tree

4 files changed

+121
-122
lines changed

4 files changed

+121
-122
lines changed
Lines changed: 101 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
23
import 'package:flutter_map/flutter_map.dart';
34
import 'package:flutter_map_example/widgets/drawer.dart';
45
import 'package:latlong2/latlong.dart';
@@ -9,128 +10,103 @@ class InteractiveTestPage extends StatefulWidget {
910
const InteractiveTestPage({Key? key}) : super(key: key);
1011

1112
@override
12-
State createState() {
13-
return _InteractiveTestPageState();
14-
}
13+
State createState() => _InteractiveTestPageState();
1514
}
1615

1716
class _InteractiveTestPageState extends State<InteractiveTestPage> {
18-
// Enable pinchZoom and doubleTapZoomBy by default
19-
int flags = InteractiveFlag.pinchZoom | InteractiveFlag.doubleTapZoom;
20-
21-
MapEvent? _latestEvent;
22-
23-
@override
24-
void initState() {
25-
super.initState();
26-
}
17+
static const availableFlags = {
18+
'Movement': {
19+
InteractiveFlag.drag: 'Drag',
20+
InteractiveFlag.flingAnimation: 'Fling',
21+
InteractiveFlag.pinchMove: 'Pinch',
22+
},
23+
'Zooming': {
24+
InteractiveFlag.pinchZoom: 'Pinch',
25+
InteractiveFlag.scrollWheelZoom: 'Scroll',
26+
InteractiveFlag.doubleTapZoom: 'Double tap',
27+
InteractiveFlag.doubleTapDragZoom: '+ drag',
28+
},
29+
'Rotation': {
30+
InteractiveFlag.rotate: 'Twist',
31+
},
32+
};
2733

28-
void onMapEvent(MapEvent mapEvent) {
29-
if (mapEvent is! MapEventMove && mapEvent is! MapEventRotate) {
30-
// do not flood console with move and rotate events
31-
debugPrint(_eventName(mapEvent));
32-
}
33-
34-
setState(() {
35-
_latestEvent = mapEvent;
36-
});
37-
}
34+
int flags = InteractiveFlag.drag | InteractiveFlag.pinchZoom;
35+
bool keyboardCursorRotate = false;
3836

39-
void updateFlags(int flag) {
40-
if (InteractiveFlag.hasFlag(flags, flag)) {
41-
// remove flag from flags
42-
flags &= ~flag;
43-
} else {
44-
// add flag to flags
45-
flags |= flag;
46-
}
47-
}
37+
MapEvent? _latestEvent;
4838

4939
@override
5040
Widget build(BuildContext context) {
5141
return Scaffold(
52-
appBar: AppBar(title: const Text('Test out Interactive flags!')),
42+
appBar: AppBar(title: const Text('Interactive Flags')),
5343
drawer: buildDrawer(context, InteractiveTestPage.route),
5444
body: Padding(
5545
padding: const EdgeInsets.all(8),
5646
child: Column(
5747
children: [
58-
Row(
59-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
60-
children: <Widget>[
61-
MaterialButton(
62-
color: InteractiveFlag.hasDrag(flags)
63-
? Colors.greenAccent
64-
: Colors.redAccent,
65-
onPressed: () {
66-
setState(() {
67-
updateFlags(InteractiveFlag.drag);
68-
});
69-
},
70-
child: const Text('Drag'),
71-
),
72-
MaterialButton(
73-
color: InteractiveFlag.hasFlingAnimation(flags)
74-
? Colors.greenAccent
75-
: Colors.redAccent,
76-
onPressed: () {
77-
setState(() {
78-
updateFlags(InteractiveFlag.flingAnimation);
79-
});
80-
},
81-
child: const Text('Fling'),
82-
),
83-
MaterialButton(
84-
color: InteractiveFlag.hasPinchMove(flags)
85-
? Colors.greenAccent
86-
: Colors.redAccent,
87-
onPressed: () {
88-
setState(() {
89-
updateFlags(InteractiveFlag.pinchMove);
90-
});
91-
},
92-
child: const Text('Pinch move'),
93-
),
94-
],
95-
),
96-
Row(
97-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
98-
children: <Widget>[
99-
MaterialButton(
100-
color: InteractiveFlag.hasDoubleTapZoom(flags)
101-
? Colors.greenAccent
102-
: Colors.redAccent,
103-
onPressed: () {
104-
setState(() {
105-
updateFlags(InteractiveFlag.doubleTapZoom);
106-
});
107-
},
108-
child: const Text('Double tap zoom'),
109-
),
110-
MaterialButton(
111-
color: InteractiveFlag.hasRotate(flags)
112-
? Colors.greenAccent
113-
: Colors.redAccent,
114-
onPressed: () {
115-
setState(() {
116-
updateFlags(InteractiveFlag.rotate);
117-
});
118-
},
119-
child: const Text('Rotate'),
120-
),
121-
MaterialButton(
122-
color: InteractiveFlag.hasPinchZoom(flags)
123-
? Colors.greenAccent
124-
: Colors.redAccent,
125-
onPressed: () {
126-
setState(() {
127-
updateFlags(InteractiveFlag.pinchZoom);
128-
});
129-
},
130-
child: const Text('Pinch zoom'),
131-
),
132-
],
48+
Flex(
49+
direction: MediaQuery.of(context).size.width >= 600
50+
? Axis.horizontal
51+
: Axis.vertical,
52+
mainAxisSize: MainAxisSize.max,
53+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
54+
children: availableFlags.entries
55+
.map<Widget?>(
56+
(category) => Column(
57+
children: [
58+
Text(
59+
category.key,
60+
style: const TextStyle(fontWeight: FontWeight.bold),
61+
),
62+
Row(
63+
mainAxisSize: MainAxisSize.min,
64+
children: <Widget>[
65+
...category.value.entries.map(
66+
(e) => Column(
67+
children: [
68+
Checkbox.adaptive(
69+
value:
70+
InteractiveFlag.hasFlag(e.key, flags),
71+
onChanged: (enabled) {
72+
if (!enabled!) {
73+
setState(() => flags &= ~e.key);
74+
return;
75+
}
76+
setState(() => flags |= e.key);
77+
},
78+
),
79+
Text(e.value),
80+
],
81+
),
82+
),
83+
if (category.key == 'Rotation') ...[
84+
Column(
85+
children: [
86+
Checkbox.adaptive(
87+
value: keyboardCursorRotate,
88+
onChanged: (enabled) => setState(
89+
() => keyboardCursorRotate = enabled!),
90+
),
91+
const Text('Cursor & CTRL'),
92+
],
93+
),
94+
]
95+
].interleave(const SizedBox(width: 12)).toList()
96+
..removeLast(),
97+
)
98+
],
99+
),
100+
)
101+
.interleave(
102+
MediaQuery.of(context).size.width >= 600
103+
? null
104+
: const SizedBox(height: 12),
105+
)
106+
.whereType<Widget>()
107+
.toList(),
133108
),
109+
const Divider(),
134110
Padding(
135111
padding: const EdgeInsets.only(top: 8, bottom: 8),
136112
child: Center(
@@ -140,14 +116,21 @@ class _InteractiveTestPageState extends State<InteractiveTestPage> {
140116
),
141117
),
142118
),
143-
Flexible(
119+
Expanded(
144120
child: FlutterMap(
145121
options: MapOptions(
146-
onMapEvent: onMapEvent,
122+
onMapEvent: (evt) => setState(() => _latestEvent = evt),
147123
initialCenter: const LatLng(51.5, -0.09),
148124
initialZoom: 11,
149125
interactionOptions: InteractionOptions(
150126
flags: flags,
127+
isCursorRotationKeyboardKeyTrigger: (key) =>
128+
keyboardCursorRotate &&
129+
{
130+
LogicalKeyboardKey.control,
131+
LogicalKeyboardKey.controlLeft,
132+
LogicalKeyboardKey.controlRight
133+
}.contains(key),
151134
),
152135
),
153136
children: [
@@ -210,3 +193,12 @@ class _InteractiveTestPageState extends State<InteractiveTestPage> {
210193
}
211194
}
212195
}
196+
197+
extension _IterableExt<E> on Iterable<E> {
198+
Iterable<E> interleave(E separator) sync* {
199+
for (int i = 0; i < length; i++) {
200+
yield elementAt(i);
201+
if (i < length) yield separator;
202+
}
203+
}
204+
}

lib/src/gestures/flutter_map_interactive_viewer.dart

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class FlutterMapInteractiveViewerState
4040
extends State<FlutterMapInteractiveViewer> with TickerProviderStateMixin {
4141
static const int _kMinFlingVelocity = 800;
4242
static const _kDoubleTapZoomDuration = 200;
43-
static const doubleTapDelay = Duration(milliseconds: 350);
43+
static const doubleTapDelay = Duration(milliseconds: 250);
4444

4545
final _positionedTapController = PositionedTapController();
4646
final _gestureArenaTeam = GestureArenaTeam();
@@ -210,13 +210,11 @@ class FlutterMapInteractiveViewerState
210210
widget.controller.moveEnded(MapEventSource.interactiveFlagsChanged);
211211
}
212212

213-
if (oldOptions.isCursorRotationKeyboardKeyTrigger !=
214-
newOptions.isCursorRotationKeyboardKeyTrigger) {
215-
ServicesBinding.instance.keyboard
216-
.removeHandler(keyboardRotationTriggerKeyHandler);
217-
ServicesBinding.instance.keyboard
218-
.addHandler(keyboardRotationTriggerKeyHandler);
219-
}
213+
// No way to detect whether two functions are equal, so assume they aren't
214+
ServicesBinding.instance.keyboard
215+
.removeHandler(keyboardRotationTriggerKeyHandler);
216+
ServicesBinding.instance.keyboard
217+
.addHandler(keyboardRotationTriggerKeyHandler);
220218
}
221219

222220
Map<Type, GestureRecognizerFactory> _createGestures({
@@ -841,7 +839,7 @@ class FlutterMapInteractiveViewerState
841839
_doubleTapHoldMaxDelay?.cancel();
842840

843841
final flags = _interactionOptions.flags;
844-
if (InteractiveFlag.hasPinchZoom(flags)) {
842+
if (InteractiveFlag.hasDoubleTapDragZoom(flags)) {
845843
final verticalOffset = (_focalStartLocal - details.localFocalPoint).dy;
846844
final newZoom = _mapZoomStart - verticalOffset / 360 * _camera.zoom;
847845

lib/src/gestures/interactive_flag.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:flutter_map/src/map/options.dart';
1+
import 'package:flutter_map/flutter_map.dart';
22

33
/// Use [InteractiveFlag] to disable / enable certain events Use
44
/// [InteractiveFlag.all] to enable all events, use [InteractiveFlag.none] to
@@ -35,14 +35,19 @@ abstract class InteractiveFlag {
3535
/// Enable zooming with a single-finger double tap gesture
3636
static const int doubleTapZoom = 1 << 4;
3737

38+
/// Enable zooming with a single-finger double-tap-drag gesture
39+
///
40+
/// The associated [MapEventSource] is [MapEventSource.doubleTapHold].
41+
static const int doubleTapDragZoom = 1 << 5;
42+
3843
/// Enable zooming with a mouse scroll wheel
39-
static const int scrollWheelZoom = 1 << 5;
44+
static const int scrollWheelZoom = 1 << 6;
4045

4146
/// Enable rotation with two-finger twist gesture
4247
///
4348
/// For controlling rotation where a keyboard/cursor combination is used, see
4449
/// [InteractionOptions.isCursorRotationKeyboardKeyTrigger].
45-
static const int rotate = 1 << 6;
50+
static const int rotate = 1 << 7;
4651

4752
/// Flags pertaining to gestures which require multiple fingers.
4853
static const _multiFingerFlags = pinchMove | pinchZoom | rotate;
@@ -71,6 +76,10 @@ abstract class InteractiveFlag {
7176
/// True if the [pinchZoom] interactive flag is enabled.
7277
static bool hasPinchZoom(int flags) => hasFlag(flags, pinchZoom);
7378

79+
/// True if the [doubleTapDragZoom] interactive flag is enabled.
80+
static bool hasDoubleTapDragZoom(int flags) =>
81+
hasFlag(flags, doubleTapDragZoom);
82+
7483
/// True if the [doubleTapZoom] interactive flag is enabled.
7584
static bool hasDoubleTapZoom(int flags) => hasFlag(flags, doubleTapZoom);
7685

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_map
22
description: A versatile mapping package for Flutter, that's simple and easy to learn, yet completely customizable and configurable.
3-
version: 6.0.0-dev.1
3+
version: 6.0.0-dev.2
44

55
repository: https://github.com/fleaflet/flutter_map
66
issue_tracker: https://github.com/fleaflet/flutter_map/issues

0 commit comments

Comments
 (0)