Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added InteractiveFlag.doubleTapDragZoom #1603

Merged
merged 3 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 101 additions & 109 deletions example/lib/pages/interactive_test_page.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_example/widgets/drawer.dart';
import 'package:latlong2/latlong.dart';
Expand All @@ -9,128 +10,103 @@ class InteractiveTestPage extends StatefulWidget {
const InteractiveTestPage({Key? key}) : super(key: key);

@override
State createState() {
return _InteractiveTestPageState();
}
State createState() => _InteractiveTestPageState();
}

class _InteractiveTestPageState extends State<InteractiveTestPage> {
// Enable pinchZoom and doubleTapZoomBy by default
int flags = InteractiveFlag.pinchZoom | InteractiveFlag.doubleTapZoom;

MapEvent? _latestEvent;

@override
void initState() {
super.initState();
}
static const availableFlags = {
'Movement': {
InteractiveFlag.drag: 'Drag',
InteractiveFlag.flingAnimation: 'Fling',
InteractiveFlag.pinchMove: 'Pinch',
},
'Zooming': {
InteractiveFlag.pinchZoom: 'Pinch',
InteractiveFlag.scrollWheelZoom: 'Scroll',
InteractiveFlag.doubleTapZoom: 'Double tap',
InteractiveFlag.doubleTapDragZoom: '+ drag',
},
'Rotation': {
InteractiveFlag.rotate: 'Twist',
},
};

void onMapEvent(MapEvent mapEvent) {
if (mapEvent is! MapEventMove && mapEvent is! MapEventRotate) {
// do not flood console with move and rotate events
debugPrint(_eventName(mapEvent));
}

setState(() {
_latestEvent = mapEvent;
});
}
int flags = InteractiveFlag.drag | InteractiveFlag.pinchZoom;
bool keyboardCursorRotate = false;

void updateFlags(int flag) {
if (InteractiveFlag.hasFlag(flags, flag)) {
// remove flag from flags
flags &= ~flag;
} else {
// add flag to flags
flags |= flag;
}
}
MapEvent? _latestEvent;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Test out Interactive flags!')),
appBar: AppBar(title: const Text('Interactive Flags')),
drawer: buildDrawer(context, InteractiveTestPage.route),
body: Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
MaterialButton(
color: InteractiveFlag.hasDrag(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.drag);
});
},
child: const Text('Drag'),
),
MaterialButton(
color: InteractiveFlag.hasFlingAnimation(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.flingAnimation);
});
},
child: const Text('Fling'),
),
MaterialButton(
color: InteractiveFlag.hasPinchMove(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.pinchMove);
});
},
child: const Text('Pinch move'),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
MaterialButton(
color: InteractiveFlag.hasDoubleTapZoom(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.doubleTapZoom);
});
},
child: const Text('Double tap zoom'),
),
MaterialButton(
color: InteractiveFlag.hasRotate(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.rotate);
});
},
child: const Text('Rotate'),
),
MaterialButton(
color: InteractiveFlag.hasPinchZoom(flags)
? Colors.greenAccent
: Colors.redAccent,
onPressed: () {
setState(() {
updateFlags(InteractiveFlag.pinchZoom);
});
},
child: const Text('Pinch zoom'),
),
],
Flex(
direction: MediaQuery.of(context).size.width >= 600
? Axis.horizontal
: Axis.vertical,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: availableFlags.entries
.map<Widget?>(
(category) => Column(
children: [
Text(
category.key,
style: const TextStyle(fontWeight: FontWeight.bold),
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
...category.value.entries.map(
(e) => Column(
children: [
Checkbox.adaptive(
value:
InteractiveFlag.hasFlag(e.key, flags),
onChanged: (enabled) {
if (!enabled!) {
setState(() => flags &= ~e.key);
return;
}
setState(() => flags |= e.key);
},
),
Text(e.value),
],
),
),
if (category.key == 'Rotation') ...[
Column(
children: [
Checkbox.adaptive(
value: keyboardCursorRotate,
onChanged: (enabled) => setState(
() => keyboardCursorRotate = enabled!),
),
const Text('Cursor & CTRL'),
],
),
]
].interleave(const SizedBox(width: 12)).toList()
..removeLast(),
)
],
),
)
.interleave(
MediaQuery.of(context).size.width >= 600
? null
: const SizedBox(height: 12),
)
.whereType<Widget>()
.toList(),
),
const Divider(),
Padding(
padding: const EdgeInsets.only(top: 8, bottom: 8),
child: Center(
Expand All @@ -140,14 +116,21 @@ class _InteractiveTestPageState extends State<InteractiveTestPage> {
),
),
),
Flexible(
Expanded(
child: FlutterMap(
options: MapOptions(
onMapEvent: onMapEvent,
onMapEvent: (evt) => setState(() => _latestEvent = evt),
initialCenter: const LatLng(51.5, -0.09),
initialZoom: 11,
interactionOptions: InteractionOptions(
flags: flags,
isCursorRotationKeyboardKeyTrigger: (key) =>
keyboardCursorRotate &&
{
LogicalKeyboardKey.control,
LogicalKeyboardKey.controlLeft,
LogicalKeyboardKey.controlRight
}.contains(key),
),
),
children: [
Expand Down Expand Up @@ -210,3 +193,12 @@ class _InteractiveTestPageState extends State<InteractiveTestPage> {
}
}
}

extension _IterableExt<E> on Iterable<E> {
Iterable<E> interleave(E separator) sync* {
for (int i = 0; i < length; i++) {
yield elementAt(i);
if (i < length) yield separator;
}
}
}
16 changes: 7 additions & 9 deletions lib/src/gestures/flutter_map_interactive_viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class FlutterMapInteractiveViewerState
extends State<FlutterMapInteractiveViewer> with TickerProviderStateMixin {
static const int _kMinFlingVelocity = 800;
static const _kDoubleTapZoomDuration = 200;
static const doubleTapDelay = Duration(milliseconds: 350);
static const doubleTapDelay = Duration(milliseconds: 250);

final _positionedTapController = PositionedTapController();
final _gestureArenaTeam = GestureArenaTeam();
Expand Down Expand Up @@ -210,13 +210,11 @@ class FlutterMapInteractiveViewerState
widget.controller.moveEnded(MapEventSource.interactiveFlagsChanged);
}

if (oldOptions.isCursorRotationKeyboardKeyTrigger !=
newOptions.isCursorRotationKeyboardKeyTrigger) {
ServicesBinding.instance.keyboard
.removeHandler(keyboardRotationTriggerKeyHandler);
ServicesBinding.instance.keyboard
.addHandler(keyboardRotationTriggerKeyHandler);
}
// No way to detect whether two functions are equal, so assume they aren't
ServicesBinding.instance.keyboard
.removeHandler(keyboardRotationTriggerKeyHandler);
ServicesBinding.instance.keyboard
.addHandler(keyboardRotationTriggerKeyHandler);
}

Map<Type, GestureRecognizerFactory> _createGestures({
Expand Down Expand Up @@ -841,7 +839,7 @@ class FlutterMapInteractiveViewerState
_doubleTapHoldMaxDelay?.cancel();

final flags = _interactionOptions.flags;
if (InteractiveFlag.hasPinchZoom(flags)) {
if (InteractiveFlag.hasDoubleTapDragZoom(flags)) {
final verticalOffset = (_focalStartLocal - details.localFocalPoint).dy;
final newZoom = _mapZoomStart - verticalOffset / 360 * _camera.zoom;

Expand Down
15 changes: 12 additions & 3 deletions lib/src/gestures/interactive_flag.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'package:flutter_map/src/map/options.dart';
import 'package:flutter_map/flutter_map.dart';

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

/// Enable zooming with a single-finger double-tap-drag gesture
///
/// The associated [MapEventSource] is [MapEventSource.doubleTapHold].
static const int doubleTapDragZoom = 1 << 5;

/// Enable zooming with a mouse scroll wheel
static const int scrollWheelZoom = 1 << 5;
static const int scrollWheelZoom = 1 << 6;

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

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

/// True if the [doubleTapDragZoom] interactive flag is enabled.
static bool hasDoubleTapDragZoom(int flags) =>
hasFlag(flags, doubleTapDragZoom);

/// True if the [doubleTapZoom] interactive flag is enabled.
static bool hasDoubleTapZoom(int flags) => hasFlag(flags, doubleTapZoom);

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_map
description: A versatile mapping package for Flutter, that's simple and easy to learn, yet completely customizable and configurable.
version: 6.0.0-dev.1
version: 6.0.0-dev.2

repository: https://github.com/fleaflet/flutter_map
issue_tracker: https://github.com/fleaflet/flutter_map/issues
Expand Down