External Custom Controllers

For more information about what a MapController is, and when it is necessary to set one up in this way, see:

Controllers & Cameras

Basic Setup

The FlutterMap.controller parameter takes an externally intialised MapController instance, and attaches it to the map.

// Within a widget
final mapController = MapController();

@override
Widget build(BuildContext context) =>
    FlutterMap(
        mapController: mapController,
        // ...
    );

Usage Before Attachment (eg. Within initState)

It is not safe to assume that the MapController is ready to use as soon as an instance has been initialised, for example within initState.

It must first be attached to the FlutterMap, which could take up to multiple frames to occur (similar to the way a ScrollController is attached to a scrollable view). It helps to avoid errors by thinking of the controller in this way.

For example, it is sometimes necessary to use a controller in the initState() method (for example to attach an event listener). However, because this method executes before the widget has been built, a controller defined here will not be ready for use.

Instead, use the MapOptions.onMapReady callback. At this point, it is guaranteed that the controller will have been attached. You could also use this method to complete a Completer (and await its Future elsewhere) if you need to use it elsewhere.

final mapController = MapController();

@override
void initState() {
    // Cannot use `mapController` safely here
}

@override
Widget build(BuildContext context) {
    return FlutterMap(
        mapController: mapController,
        options: MapOptions(
            onMapReady: () {
                mapController.mapEventStream.listen((evt) {}); // for example
                // Any* other `MapController` dependent methods
            },
        ),
    );
}

Usage Within A State System/Model

Instead, some extra care should be taken, which may feel a little backwards at first. The state model should be used AFTER the normal setup.

  1. Setup the controller as in Basic Setup, where the MapController is defined & initialised directly adjacent to the FlutterMap

  2. In your state model, create a nullable (and initially uninitialised) MapController containing field

  3. Follow Usage Before Attachment (eg. Within initState) to setup an onMapReady callback. Then within this callback, set the state model field.

It may then be beneficial to unset the state model field when the controller is disposed: it should be disposed when the FlutterMap is disposed, which should occur just before the widget building the FlutterMap is disposed. Therefore, you can override the dispose method.

Animation

Whilst animated movements through MapControllers aren't built-in, the community maintained plugin flutter_map_animations provides this, and much more!

Last updated

Was this helpful?