Skip to content

[google_maps_flutter] Support EdgeInsets in CameraUpdate.newLatLngBounds for asymmetric padding #183439

@benji-farquhar

Description

@benji-farquhar

Use case

Apps that place panels, sheets, or sidebars over the map (e.g., a details card on the left, a bottom sheet on mobile) need to set asymmetric GoogleMap(padding: EdgeInsets) so Google Maps knows where the "visible area" is. When a marker is selected, the camera needs to recenter within that padded visible area.

Currently, changing the widget-level padding and calling animateCamera are two independent operations with no coordination. This causes competing animations when the padding changes at the same time as the camera needs to recenter:

  1. Padding changes → Google Maps shifts the viewport (visible jump)
  2. animateCamera fires → but may use stale padding for its target calculation, causing the camera to wobble or reverse direction mid-animation

The workaround is to set the padding instantly (causing a visible viewport jump), wait a frame for Maps to process it, then call animateCamera. This works but produces a noticeable two-step motion rather than one smooth animation.

Proposal

Add an EdgeInsets parameter to CameraUpdate.newLatLngBounds:

// Current API - only uniform padding
static CameraUpdate newLatLngBounds(LatLngBounds bounds, double padding)

// Proposed addition - asymmetric padding
static CameraUpdate newLatLngBoundsWithEdgeInsets(LatLngBounds bounds, EdgeInsets padding)

This would allow the camera update to atomically calculate the target position using the specified asymmetric padding, rather than relying on the widget-level padding being set and processed first.

Native SDK evidence

iOS ✅ Already supported

The iOS Google Maps SDK already provides GMSCameraUpdate.fitBounds(_:withEdgeInsets:) which accepts UIEdgeInsets with individual top/left/bottom/right values:

GMSCameraUpdate *update = [GMSCameraUpdate fitBounds:bounds withEdgeInsets:UIEdgeInsetsMake(top, left, bottom, right)];
[mapView animateWithCameraUpdate:update];

This is a direct 1:1 mapping. The Flutter plugin simply isn't exposing this existing native capability.

Reference: GMSCameraUpdate Class Reference

Web ✅ Already supported

The Google Maps JavaScript API's fitBounds method accepts a padding parameter with individual top, right, bottom, left values:

map.fitBounds(bounds, { top: 80, right: 16, bottom: 350, left: 16 });

This is a direct mapping via the google_maps Dart package's gmaps.Padding object.

Android ⚠️ No direct equivalent

Android's CameraUpdateFactory.newLatLngBounds(LatLngBounds, int) only accepts uniform padding. Unlike iOS and Web, there is no newLatLngBounds variant that accepts asymmetric edge insets.

Note: GoogleMap.setPadding(int left, int top, int right, int bottom) is not a viable workaround here — it serves a fundamentally different purpose. setPadding defines the map's "usable area", permanently repositioning the Google logo, legal text, compass, and zoom controls. It should not be temporarily mutated to simulate per-camera-update insets.

Possible approaches for Android:

  1. Manual camera calculation — The Flutter Android plugin could compute the target CameraPosition (center + zoom) by taking the bounds, the requested edge insets, and the current viewport dimensions, effectively reimplementing what iOS's fitBounds:withEdgeInsets: does natively. This is self-contained and shippable without upstream changes.

  2. Upstream SDK feature request — File a feature request on the Google Maps Platform issue tracker for a CameraUpdateFactory.newLatLngBounds(LatLngBounds, int, int, int, int) overload, bringing Android to parity with iOS. This would allow a clean 1:1 mapping but is dependent on Google's prioritisation.

Current Flutter plugin version

google_maps_flutter: 2.14.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listc: new featureNothing broken; request for a new capabilityp: mapsGoogle Maps pluginpackageflutter/packages repository. See also p: labels.team-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions