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

Disable Scroll Zoom in Flutter ​

This tutorial shows how to disable or control zoom gestures on your MapMetrics Flutter map. This is useful for maps embedded in scrollable pages where pinch-to-zoom conflicts with page scrolling.

Prerequisites ​

Before you begin, ensure you have:

Disable Zoom Gestures ​

Gestures are configured via a MapGestures value on MapOptions.gestures, not individual booleans on the map widget. Pass MapGestures.all(zoom: false) to disable pinch-to-zoom and double-tap-to-zoom while leaving everything else on:

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

class DisableZoomScreen extends StatefulWidget {
  @override
  _DisableZoomScreenState createState() => _DisableZoomScreenState();
}

class _DisableZoomScreenState extends State<DisableZoomScreen> {
  MapController? mapController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Zoom Disabled')),
      body: MapMetricsView(
        options: MapOptions(
          initCenter: Position(2.3522, 48.8566),
          initZoom: 13.0,
          initStyle: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
          gestures: const MapGestures.all(zoom: false), // Disables pinch-to-zoom
        ),
        onMapCreated: (controller) => mapController = controller,
      ),
    );
  }
}

The map displays normally but users cannot zoom with gestures. You can still zoom programmatically with mapController?.animateCamera(zoom: ...).

Disable All Gestures ​

Lock the map completely — no pan, zoom, rotation, or tilt — with MapGestures.none():

dart
MapMetricsView(
  options: MapOptions(
    initCenter: Position(2.3522, 48.8566),
    initZoom: 13.0,
    initStyle: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
    gestures: const MapGestures.none(),
  ),
  onMapCreated: (controller) => mapController = controller,
)

Toggle Zoom On/Off ​

Let users enable or disable zoom with a switch. Since gestures live on MapOptions, rebuild it in setState:

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

class ToggleZoomScreen extends StatefulWidget {
  @override
  _ToggleZoomScreenState createState() => _ToggleZoomScreenState();
}

class _ToggleZoomScreenState extends State<ToggleZoomScreen> {
  MapController? mapController;
  bool zoomEnabled = true;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Toggle Zoom'),
        actions: [
          Row(
            children: [
              Text(
                zoomEnabled ? 'Zoom ON' : 'Zoom OFF',
                style: TextStyle(color: Colors.white),
              ),
              Switch(
                value: zoomEnabled,
                onChanged: (value) {
                  setState(() {
                    zoomEnabled = value;
                  });
                },
                activeColor: Colors.white,
              ),
            ],
          ),
        ],
      ),
      body: MapMetricsView(
        options: MapOptions(
          initCenter: Position(2.3522, 48.8566),
          initZoom: 13.0,
          initStyle: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
          gestures: MapGestures.all(zoom: zoomEnabled),
        ),
        onMapCreated: (controller) => mapController = controller,
      ),
    );
  }
}

Embedded Map in Scrollable Page ​

A common pattern: disable gestures on an embedded map, then provide a "tap to interact" overlay:

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

class EmbeddedMapScreen extends StatefulWidget {
  @override
  _EmbeddedMapScreenState createState() => _EmbeddedMapScreenState();
}

class _EmbeddedMapScreenState extends State<EmbeddedMapScreen> {
  MapController? mapController;
  bool isMapActive = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Embedded Map')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            // Some content above the map
            Container(
              padding: EdgeInsets.all(20),
              child: Text(
                'Scroll down to see the map. Tap the map to interact with it.',
                style: TextStyle(fontSize: 16),
              ),
            ),
            // Embedded map with tap-to-activate
            Container(
              height: 300,
              margin: EdgeInsets.all(16),
              clipBehavior: Clip.hardEdge,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(12),
                border: Border.all(color: Colors.grey[300]!),
              ),
              child: Stack(
                children: [
                  MapMetricsView(
                    options: MapOptions(
                      initCenter: Position(2.3522, 48.8566),
                      initZoom: 13.0,
                      initStyle: 'https://gateway.mapmetrics-atlas.net/styles/?fileName=YOUR_STYLE_ID/YOUR_STYLE.json&token=YOUR_API_KEY',
                      gestures: MapGestures.all(
                        zoom: isMapActive,
                        pan: isMapActive,
                        rotate: isMapActive,
                      ),
                    ),
                    onMapCreated: (controller) => mapController = controller,
                  ),
                  // Overlay: tap to activate
                  if (!isMapActive)
                    GestureDetector(
                      onTap: () {
                        setState(() {
                          isMapActive = true;
                        });
                      },
                      child: Container(
                        color: Colors.transparent,
                        alignment: Alignment.center,
                        child: Container(
                          padding: EdgeInsets.symmetric(
                            horizontal: 16,
                            vertical: 10,
                          ),
                          decoration: BoxDecoration(
                            color: Colors.black54,
                            borderRadius: BorderRadius.circular(8),
                          ),
                          child: Text(
                            'Tap to interact with map',
                            style: TextStyle(color: Colors.white),
                          ),
                        ),
                      ),
                    ),
                ],
              ),
            ),
            // More content below
            Container(
              padding: EdgeInsets.all(20),
              child: Text(
                'More content below the map...',
                style: TextStyle(fontSize: 16),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Gesture Properties ​

MapGestures (passed as MapOptions.gestures) has four boolean fields, all true by default via MapGestures.all(...):

PropertyTypeDefaultDescription
zoombooltruePinch-to-zoom and double-tap zoom
panbooltruePan/drag to move the map
rotatebooltrueTwo-finger rotation
pitchbooltrueTwo-finger tilt for 3D perspective

Next Steps ​


Tip: When embedding a map in a scrollable page, always disable pan gestures so the page scroll works normally. Provide a "tap to interact" overlay to let users opt in.