Skip to content

Locate the User in Flutter

Show the user's current GPS location on the map. This guide covers enabling the built-in location layer and requesting location permissions on both Android and iOS.

Prerequisites

Before you begin, ensure you have:

Platform Permissions

Android

Add these permissions to android/app/src/main/AndroidManifest.xml:

xml
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

iOS

Add these keys to ios/Runner/Info.plist:

xml
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to your location to show it on the map.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to your location to show it on the map.</string>

Basic User Location

Enable the built-in location dot on the map:

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

class LocateUserScreen extends StatefulWidget {
  @override
  _LocateUserScreenState createState() => _LocateUserScreenState();
}

class _LocateUserScreenState extends State<LocateUserScreen> {
  MapMetricsController? mapController;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('My Location')),
      body: MapMetrics(
        styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
        onMapCreated: (MapMetricsController controller) {
          mapController = controller;
        },
        initialCameraPosition: CameraPosition(
          target: LatLng(48.8566, 2.3522),
          zoom: 4.0,
        ),
        myLocationEnabled: true,
        myLocationTrackingMode: MyLocationTrackingMode.Tracking,
        myLocationRenderMode: MyLocationRenderMode.COMPASS,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _goToMyLocation,
        child: Icon(Icons.my_location),
      ),
    );
  }

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

The blue dot appears at the user's current location, and the compass arrow shows the direction they are facing.

Location Tracking Modes

ModeDescription
MyLocationTrackingMode.NoneShows location dot but doesn't move the camera
MyLocationTrackingMode.TrackingCamera follows the user as they move
MyLocationTrackingMode.TrackingCompassCamera follows and rotates to match user heading
MyLocationTrackingMode.TrackingGPSCamera follows with GPS bearing

Location Render Modes

ModeDescription
MyLocationRenderMode.NORMALSimple blue dot
MyLocationRenderMode.COMPASSBlue dot with compass heading arrow
MyLocationRenderMode.GPSBlue dot with GPS bearing indicator

Complete Example: Locate Me Button

A complete example with a "Locate Me" button that requests permission and flies to the user's location:

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

class LocateMeScreen extends StatefulWidget {
  @override
  _LocateMeScreenState createState() => _LocateMeScreenState();
}

class _LocateMeScreenState extends State<LocateMeScreen> {
  MapMetricsController? mapController;
  String statusMessage = 'Tap the button to find your location';
  bool isLocating = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Locate Me')),
      body: Column(
        children: [
          // Status bar
          Container(
            width: double.infinity,
            padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
            color: Colors.grey[100],
            child: Row(
              children: [
                if (isLocating)
                  Padding(
                    padding: EdgeInsets.only(right: 8),
                    child: SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    ),
                  ),
                Expanded(child: Text(statusMessage)),
              ],
            ),
          ),
          // Map
          Expanded(
            child: MapMetrics(
              styleUrl: 'https://gateway.mapmetrics.org/styles/YOUR_STYLE_ID?token=YOUR_API_KEY',
              onMapCreated: (MapMetricsController controller) {
                mapController = controller;
              },
              onUserLocationUpdated: (UserLocation location) {
                setState(() {
                  isLocating = false;
                  statusMessage =
                      'Lat: ${location.position.latitude.toStringAsFixed(5)}, '
                      'Lng: ${location.position.longitude.toStringAsFixed(5)}';
                });
              },
              initialCameraPosition: CameraPosition(
                target: LatLng(0.0, 0.0),
                zoom: 2.0,
              ),
              myLocationEnabled: true,
              myLocationTrackingMode: MyLocationTrackingMode.None,
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _locateMe,
        icon: Icon(Icons.my_location),
        label: Text('Locate Me'),
      ),
    );
  }

  void _locateMe() {
    setState(() {
      isLocating = true;
      statusMessage = 'Getting your location...';
    });

    // Enable tracking and fly to user
    mapController?.animateCamera(
      CameraUpdate.zoomTo(15.0),
    );
  }
}

Handling Permission Errors

Always handle the case where the user denies location permission:

dart
MapMetrics(
  // ... other properties
  myLocationEnabled: true,
  onError: (String error) {
    if (error.contains('location') || error.contains('permission')) {
      showDialog(
        context: context,
        builder: (context) => AlertDialog(
          title: Text('Location Permission Required'),
          content: Text(
            'Please enable location permissions in your device settings '
            'to use this feature.',
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: Text('OK'),
            ),
          ],
        ),
      );
    }
  },
)

Next Steps


Note: Location only works on physical devices or emulators with location simulation enabled. It also requires HTTPS in production web builds.