maplibre / flutter-maplibre-gl

Customizable, performant and vendor-free vector and raster maps, flutter wrapper for maplibre-native and maplibre-gl-js (fork of flutter-mapbox-gl/maps)
https://pub.dev/packages/maplibre_gl
Other
228 stars 125 forks source link

moveCamera() doesn't work in onMapCreated callback #371

Open l2-map-dev opened 10 months ago

l2-map-dev commented 10 months ago

I want to initialize a map with an initial bounding box, and since initialCameraPosition appears to only support specifying a center position and zoom level, it appears the appropriate way to accomplish this is by calling moveCamera() in the onMapCreated callback like so:

onMapCreated: (mapController) {
  mapController
      .moveCamera(
    CameraUpdate.newLatLngBounds(newBounds),
}

However, this call to moveCamera doesn't seem to do anything; the camera position remains at whatever the initial camera position was set to when creating the widget.

Sleeping with a future before running the update resolves the issue, but this is obviously hacky and I'd like to find a more reliable solution.

onMapCreated: (mapController) {

Future.delayed(const Duration(milliseconds: 200), () {
  mapController
      .moveCamera(
    CameraUpdate.newLatLngBounds(newBounds),
})
}

I've also tried using

WidgetsBinding.instance.addPostFrameCallback((_) {

mapController
      .moveCamera(
    CameraUpdate.newLatLngBounds(newBounds)

});

to delay calling moveCamera() until after the widget has been initialized, and oddly, using this method, the camera moves partially to the new position, but stops before reaching the new bounding box.

I've tried all of the above in onStyleLoaded() as well with no luck. It seems as though even at the point onMapCreated() or onStyleLoaded() are run, some state still isn't initialized which prevents the camera update from functioning. Can anyone offer some help here?

m0nac0 commented 10 months ago

Can you try the onStyleLoadedCallback, please?

l2-map-dev commented 10 months ago

Thanks for the reply! As I mentioned above, I did give that a try and unfortunately it had the same result. Even in the onStyleLoadedCallback, the camera remains at its initial position. I used mapController.getVisibleRegion() to verify this and the bounds of the map are identical before and after the call to moveCamera.

LouisRaverdy commented 1 month ago

This issue specifically affects iOS devices, while it functions perfectly on Android devices. The problem originates from the onMapCreated and onStyleLoaded callbacks, which are triggered prematurely on iOS. The question is, what is not being waited for? Maybe @josxha, do you have an idea ?

josxha commented 1 month ago

Apparently, onMapCreated() and onStyleLoaded aren't save to call operations on the map from on iOS. I haven't looked at the at the ios implementation in depth. On android the onMapCreated() callback get's awaited internally to ensure the map has loaded. This callback does not exist in the iOS SDK. There seems to be some code in swift to work around this but it's currently not clear to me why it is done the way it is.

https://github.com/maplibre/flutter-maplibre-gl/blob/5a3daa23a46cd14b97c4348f2295c97f7a151086/maplibre_gl/ios/maplibre_gl/Sources/maplibre_gl/MapLibreMapController.swift#L130-L143

LouisRaverdy commented 1 month ago

I see now, thanks for the clarification. The problem is that there isn't a proper solution, which is really frustrating. The only workaround so far is to add a delay.

josxha commented 1 month ago

Yep, I agree. Have you tried to enforce the viewport of the map with the cameraTargetBounds parameter and changing the bounds afterwards to unbound? (Problably again after a delay)