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.