Skip to content

Both copy text to your clipboard — Build with AI copies a setup prompt to paste into Claude Code, Cursor, Codex or Copilot; Copy page as Markdown copies this page to paste into a chat. How it works

Toggle Map Interactions in Flutter

This tutorial shows how to enable and disable individual map interactions like zoom, pan, rotate, and tilt at runtime.

Prerequisites

Before you begin, ensure you have:

A Note on Gesture Control

There are no individual zoomGesturesEnabled/scrollGesturesEnabled/rotateGesturesEnabled/tiltGesturesEnabled parameters on MapMetricsView. Instead, MapOptions.gestures takes a single MapGestures object with rotate, pan, zoom, and pitch booleans. Rebuild it (via setState) whenever you want to flip a gesture — the map picks up the new MapGestures on the next MapOptions it receives, same as any other declarative widget property.

Complete Example: Interaction Control Panel

A full control panel that lets users toggle each gesture type independently:

dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';

class ToggleInteractionsScreen extends StatefulWidget {
  @override
  _ToggleInteractionsScreenState createState() => _ToggleInteractionsScreenState();
}

class _ToggleInteractionsScreenState extends State<ToggleInteractionsScreen> {
  MapController? mapController;

  bool zoomGestures = true;
  bool scrollGestures = true;
  bool rotateGestures = true;
  bool tiltGestures = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Toggle Interactions'),
        actions: [
          TextButton(
            onPressed: _enableAll,
            child: Text('All ON', style: TextStyle(color: Colors.white)),
          ),
          TextButton(
            onPressed: _disableAll,
            child: Text('All OFF', style: TextStyle(color: Colors.white70)),
          ),
        ],
      ),
      body: Column(
        children: [
          // Interaction toggles
          Container(
            padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
            color: Colors.grey[100],
            child: Column(
              children: [
                _interactionToggle(
                  'Zoom (pinch)',
                  Icons.zoom_in,
                  zoomGestures,
                  (v) => setState(() => zoomGestures = v),
                ),
                _interactionToggle(
                  'Scroll (pan)',
                  Icons.pan_tool,
                  scrollGestures,
                  (v) => setState(() => scrollGestures = v),
                ),
                _interactionToggle(
                  'Rotate (two-finger)',
                  Icons.rotate_right,
                  rotateGestures,
                  (v) => setState(() => rotateGestures = v),
                ),
                _interactionToggle(
                  'Tilt (two-finger vertical)',
                  Icons.view_in_ar,
                  tiltGestures,
                  (v) => setState(() => tiltGestures = v),
                ),
              ],
            ),
          ),
          // Map
          Expanded(
            child: MapMetricsView(
              options: MapOptions(
                initStyle:
                    'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
                initCenter: Position(2.3522, 48.8566), // lng, lat — Paris
                initZoom: 13.0,
                gestures: MapGestures(
                  zoom: zoomGestures,
                  pan: scrollGestures,
                  rotate: rotateGestures,
                  pitch: tiltGestures,
                ),
              ),
              onMapCreated: (controller) => mapController = controller,
            ),
          ),
        ],
      ),
    );
  }

  Widget _interactionToggle(
    String label,
    IconData icon,
    bool value,
    ValueChanged<bool> onChanged,
  ) {
    return SwitchListTile(
      title: Row(
        children: [
          Icon(icon, size: 20, color: value ? Colors.blue : Colors.grey),
          SizedBox(width: 8),
          Text(label, style: TextStyle(fontSize: 14)),
        ],
      ),
      value: value,
      onChanged: onChanged,
      dense: true,
      contentPadding: EdgeInsets.symmetric(horizontal: 8),
    );
  }

  void _enableAll() {
    setState(() {
      zoomGestures = true;
      scrollGestures = true;
      rotateGestures = true;
      tiltGestures = true;
    });
  }

  void _disableAll() {
    setState(() {
      zoomGestures = false;
      scrollGestures = false;
      rotateGestures = false;
      tiltGestures = false;
    });
  }
}

Presentation Mode

A common use case: lock all interactions for a presentation or kiosk display, then unlock with a button:

dart
import 'package:flutter/material.dart';
import 'package:mapmetrics/mapmetrics.dart';

class PresentationModeScreen extends StatefulWidget {
  @override
  _PresentationModeScreenState createState() => _PresentationModeScreenState();
}

class _PresentationModeScreenState extends State<PresentationModeScreen> {
  MapController? mapController;
  bool isLocked = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: [
          MapMetricsView(
            options: MapOptions(
              initStyle:
                  'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
              initCenter: Position(2.3522, 48.8566),
              initZoom: 13.0,
              gestures: isLocked ? const MapGestures.none() : const MapGestures.all(),
            ),
            onMapCreated: (controller) => mapController = controller,
          ),
          // Lock indicator and toggle
          Positioned(
            top: 50,
            right: 16,
            child: GestureDetector(
              onTap: () => setState(() => isLocked = !isLocked),
              child: Container(
                padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                decoration: BoxDecoration(
                  color: isLocked ? Colors.red : Colors.green,
                  borderRadius: BorderRadius.circular(20),
                  boxShadow: [BoxShadow(color: Colors.black26, blurRadius: 4)],
                ),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Icon(
                      isLocked ? Icons.lock : Icons.lock_open,
                      color: Colors.white,
                      size: 16,
                    ),
                    SizedBox(width: 6),
                    Text(
                      isLocked ? 'Locked' : 'Unlocked',
                      style: TextStyle(color: Colors.white, fontSize: 13),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Interaction Properties Reference

MapGestures fieldGestureDefault (MapGestures.all())
zoomPinch-to-zoom, double-tap zoomtrue
panDrag/pan to move the maptrue
rotateTwo-finger rotationtrue
pitchTwo-finger vertical swipe (3D tilt)true

Next Steps


Tip: When disabling gestures, always provide alternative controls (buttons, sliders) so users can still navigate the map.