Skip to content

Basic Map with Flutter and MapMetrics

This tutorial will show you how to create a basic interactive map using Flutter and MapMetrics Atlas API.

Basic Map Implementation

Here's a complete example of a basic map with common interactions:

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

class BasicMapScreen extends StatefulWidget {
  @override
  _BasicMapScreenState createState() => _BasicMapScreenState();
}

class _BasicMapScreenState extends State<BasicMapScreen> {
  MapMetricsController? mapController;
  LatLng? lastTappedLocation;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Basic MapMetrics Map'),
        actions: [
          IconButton(
            icon: Icon(Icons.my_location),
            onPressed: _goToUserLocation,
          ),
        ],
      ),
      body: MapMetrics(
        styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
        onMapCreated: (MapMetricsController controller) {
          setState(() {
            mapController = controller;
          });
        },
        onMapClick: (Point point, LatLng coordinates) {
          setState(() {
            lastTappedLocation = coordinates;
          });
          _showLocationInfo(coordinates);
        },
        onStyleLoaded: () {
          print('Map style loaded successfully!');
        },
        initialCameraPosition: CameraPosition(
          target: LatLng(40.7128, -74.0060), // New York City
          zoom: 10.0,
        ),
        myLocationEnabled: true,
        myLocationTrackingMode: MyLocationTrackingMode.Tracking,
        myLocationRenderMode: MyLocationRenderMode.COMPASS,
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          FloatingActionButton(
            heroTag: "zoomIn",
            onPressed: _zoomIn,
            child: Icon(Icons.add),
          ),
          SizedBox(height: 8),
          FloatingActionButton(
            heroTag: "zoomOut",
            onPressed: _zoomOut,
            child: Icon(Icons.remove),
          ),
        ],
      ),
    );
  }

  void _zoomIn() {
    mapController?.animateCamera(
      CameraUpdate.zoomIn(),
    );
  }

  void _zoomOut() {
    mapController?.animateCamera(
      CameraUpdate.zoomOut(),
    );
  }

  void _goToUserLocation() {
    mapController?.animateCamera(
      CameraUpdate.zoomTo(15.0),
    );
  }

  void _showLocationInfo(LatLng coordinates) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text('Location Information'),
          content: Text(
            'Latitude: ${coordinates.latitude.toStringAsFixed(6)}\n'
            'Longitude: ${coordinates.longitude.toStringAsFixed(6)}',
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: Text('OK'),
            ),
          ],
        );
      },
    );
  }
}

Map Configuration Options

Camera Position

Control the initial view of your map:

dart
initialCameraPosition: CameraPosition(
  target: LatLng(40.7128, -74.0060), // Center point
  zoom: 10.0,                        // Zoom level (0-22)
  bearing: 0.0,                      // Rotation in degrees
  tilt: 0.0,                         // Tilt in degrees
),

User Location

Enable user location tracking:

dart
myLocationEnabled: true,
myLocationTrackingMode: MyLocationTrackingMode.Tracking,
myLocationRenderMode: MyLocationRenderMode.COMPASS,

Map Interactions

Handle various map events:

dart
onMapCreated: (MapMetricsController controller) {
  // Called when map is created
},
onMapClick: (Point point, LatLng coordinates) {
  // Called when user taps the map
},
onMapLongClick: (Point point, LatLng coordinates) {
  // Called when user long-presses the map
},
onStyleLoaded: () {
  // Called when map style is loaded
},
onCameraIdle: () {
  // Called when camera stops moving
},

Camera Controls

Programmatic Camera Movement

dart
// Zoom to specific level
mapController?.animateCamera(CameraUpdate.zoomTo(15.0));

// Zoom in/out
mapController?.animateCamera(CameraUpdate.zoomIn());
mapController?.animateCamera(CameraUpdate.zoomOut());

// Move to specific location
mapController?.animateCamera(
  CameraUpdate.newLatLng(LatLng(37.7749, -122.4194)),
);

// Move with zoom
mapController?.animateCamera(
  CameraUpdate.newLatLngZoom(LatLng(37.7749, -122.4194), 15.0),
);

// Fit bounds
mapController?.animateCamera(
  CameraUpdate.newLatLngBounds(
    LatLngBounds(
      southwest: LatLng(37.7, -122.5),
      northeast: LatLng(37.8, -122.4),
    ),
    50.0, // padding
  ),
);

Camera Position Listeners

dart
onCameraMove: (CameraPosition position) {
  print('Camera moving: ${position.zoom}');
},
onCameraIdle: () {
  print('Camera stopped moving');
},

Map State Management

Get Current Camera Position

dart
void _getCurrentPosition() async {
  CameraPosition? position = await mapController?.getCameraPosition();
  if (position != null) {
    print('Current zoom: ${position.zoom}');
    print('Current center: ${position.target}');
  }
}

Check Map State

dart
void _checkMapState() async {
  bool? isMapReady = await mapController?.isMapReady();
  if (isMapReady == true) {
    print('Map is ready for interactions');
  }
}

Error Handling

Add error handling for better user experience:

dart
MapMetrics(
  styleUrl: 'your_style_url',
  onMapCreated: (controller) {
    mapController = controller;
  },
  onMapClick: (point, coordinates) {
    // Handle clicks
  },
  onError: (String error) {
    print('Map error: $error');
    // Show error message to user
  },
  onStyleLoaded: () {
    print('Style loaded successfully');
  },
)

Performance Tips

  1. Reuse Controller: Store the MapMetricsController in a variable to avoid recreating it
  2. Debounce Events: Use debouncing for frequent events like onCameraMove
  3. Lazy Loading: Load map data only when needed
  4. Memory Management: Dispose of controllers when not needed
dart
@override
void dispose() {
  mapController?.dispose();
  super.dispose();
}

Custom Map Controls

Create custom floating action buttons for map controls:

dart
Widget _buildMapControls() {
  return Column(
    mainAxisAlignment: MainAxisAlignment.end,
    children: [
      FloatingActionButton.small(
        heroTag: "zoomIn",
        onPressed: () => mapController?.animateCamera(CameraUpdate.zoomIn()),
        child: Icon(Icons.add),
      ),
      SizedBox(height: 8),
      FloatingActionButton.small(
        heroTag: "zoomOut",
        onPressed: () => mapController?.animateCamera(CameraUpdate.zoomOut()),
        child: Icon(Icons.remove),
      ),
      SizedBox(height: 8),
      FloatingActionButton.small(
        heroTag: "location",
        onPressed: _goToUserLocation,
        child: Icon(Icons.my_location),
      ),
    ],
  );
}

Next Steps

Now that you have a basic map working, try:


Pro Tip: Use the MapMetrics Portal to create custom map styles that match your app's design. You can customize colors, fonts, and which map features are displayed.