For the complete documentation index, see llms.txt. This page is also available as Markdown.
GUIDED

Generating An Initial Position

How to pick an initial position for the map? It has a large impact on user experience, and can be the difference between seamless usage and friction every time your app starts - so it's important to get right.

Consider what purpose the map serves, as the user will have different expectations depending on the purpose.

Static map?

This guide deals primarily with interactive maps. If you have a static map which needs to be positioned based on information from an external source, see Initial Positioning. To make the map non-interactive, an IgnorePointer widget can wrap the map, and the InteractionOptions can be set to disable all other interactions that might sneak through.

If your map is interactive, minimizing the amount of effort needed to focus on the area of interest is important. Showing the map quickly and without interruption is also important, and so the generation should be quick and invisible.

This guide has been created to show examples of 3 good practise methods, which work together to create a good user experience. Examples are given to help build this into your project throughout.

Remembering the last position

To create functionality where the map opens to where the user last left it:

  • Register an event handler (see Reacting to map events for more information)

  • Use a persistence solution like shared_preferences to store the new position when necessary

  • Asynchronously load the persisted data into memory before loading the map, ideally a long time before (such as a splash screen), then retrieve it from memory when building the map - falling back to a different solution or fixed values if unavailable

The easiest and most performant way to store the new position when necessary is to store it only when a move gesture finishes, as shown in the example below. Alternatively, MapOptions.onPositionChanged could be used with a debounce mechanism.

Approximating the user's location without permissions

To provide a better UX, particularly on the first app load when the stored last location (as described above) is most likely to be missing, fallback to another approximation rather than a fixed value (as shown in the example above). We must use a source that is provided by almost all devices and is invisible to users - such as locale information.

If you have the user pick their country of interest in the onboarding, you could also use that as the source instead.

Because it is used to provide localisation, it is not restricted by the system. It is only very approximate - it reveals a country, and can be incorrect if the user's locale set does not match their true locale - but it is better than a fixed fallback.

Flutter exposes the user's locale and country code through the PlatformDispatcher. The country code (if available) can be retrieved using the following code:

Then, the country code needs to be converted into a bounding box of the country. This can be done quickly and offline by shipping a tiny data file as an asset with the app.

At the time of writing, such a file is already compiled from Natural Earth and available as a public domain JSON file:

Once included as an asset, the following can be inserted into the block from above to generate a LatLngBounds:

Because the loading of the data file is asynchronous, this either needs to be run invisibly (such as during a splash screen), or a loader is required (such as a FutureBuilder) - but because the file is so small, this will usually be very quick.

This can then be integrated as a fallback to the 'last known position' method, if the persisted values are unavailable or null.

Using location APIs

In some cases, such as for navigation apps, the most useful and most accurate initial position will be the user's physical location.

When using this method, a marker can also be shown on the map at the user's location to give some additional feedback and clarity.

As discussed above, these APIs are not guaranteed to be useable, can be unreliable, and are likely to be slow. Therefore, it is good practise to position the map using another method quickly, then use this method in the background.

If it is clear to the user that their location is loading - such as a loading indicator on a button, or a greyed out marker at the user's last known location - and the loading can be interrupted - for example with any manual gesture on the map - then this is a good UX pattern. Although, an automated map move after loading can be jarring, so it may be beneficial to require the user to press a button before using the location to position the map (unless it is expected, such as an explicit navigation flow).

Because of the complexity of this method, it is not described here.

A community maintained plugin, flutter_map_location_marker, provides a prebuilt marker and map movement logic. Even/especially when using this plugin, take care with permission handling logic, using a package like permission_handler is recommended. UX can suffer greatly if permission request flows are buggy.

Last updated

Was this helpful?