diff --git a/lib/widgets/map/map_page.dart b/lib/widgets/map/map_page.dart index eec9436c3..955cddb05 100644 --- a/lib/widgets/map/map_page.dart +++ b/lib/widgets/map/map_page.dart @@ -429,8 +429,6 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin void _toggleOverlay() => _overlayVisible.value = !_overlayVisible.value; - // TODO TLAD [map] as of Flutter v2.5.1 / google_maps_flutter v2.0.10, toggling overlay changes the size of the map, which is an issue for Google map on Android 12 - // cf https://github.com/flutter/flutter/issues/90556 Future _onOverlayVisibleChange({bool animate = true}) async { if (_overlayVisible.value) { if (animate) { diff --git a/plugins/aves_services_google/lib/src/map.dart b/plugins/aves_services_google/lib/src/map.dart index ebbef0a9b..36822557e 100644 --- a/plugins/aves_services_google/lib/src/map.dart +++ b/plugins/aves_services_google/lib/src/map.dart @@ -57,6 +57,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi final Map, Uint8List> _markerBitmaps = {}; final StreamController> _markerBitmapReadyStreamController = StreamController.broadcast(); Uint8List? _dotMarkerBitmap; + final ValueNotifier _sizeNotifier = ValueNotifier(Size.zero); ValueNotifier get boundsNotifier => widget.boundsNotifier; @@ -68,6 +69,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + _sizeNotifier.addListener(_onSizeChange); _registerWidget(widget); } @@ -83,6 +85,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi _unregisterWidget(widget); _serviceMapController?.dispose(); WidgetsBinding.instance.removeObserver(this); + _sizeNotifier.removeListener(_onSizeChange); super.dispose(); } @@ -109,7 +112,7 @@ class _EntryGoogleMapState extends State> with WidgetsBindi case AppLifecycleState.detached: break; case AppLifecycleState.resumed: - // workaround for blank Google map when resuming app + // workaround for blank map when resuming app // cf https://github.com/flutter/flutter/issues/40284 _serviceMapController?.setMapStyle(null); break; @@ -166,60 +169,65 @@ class _EntryGoogleMapState extends State> with WidgetsBindi return ValueListenableBuilder( valueListenable: widget.overlayOpacityNotifier ?? ValueNotifier(1), builder: (context, overlayOpacity, child) { - return GoogleMap( - initialCameraPosition: CameraPosition( - bearing: -bounds.rotation, - target: _toServiceLatLng(bounds.projectedCenter), - zoom: bounds.zoom, - ), - onMapCreated: (controller) async { - _serviceMapController = controller; - final zoom = await controller.getZoomLevel(); - await _updateVisibleRegion(zoom: zoom, rotation: bounds.rotation); - if (mounted) { - setState(() {}); - } - }, - // compass disabled to use provider agnostic controls - compassEnabled: false, - mapToolbarEnabled: false, - mapType: _toMapType(widget.style), - minMaxZoomPreference: MinMaxZoomPreference(widget.minZoom, widget.maxZoom), - rotateGesturesEnabled: true, - scrollGesturesEnabled: interactive, - // zoom controls disabled to use provider agnostic controls - zoomControlsEnabled: false, - zoomGesturesEnabled: interactive, - // lite mode disabled because it lacks camera animation - liteModeEnabled: false, - // tilt disabled to match leaflet - tiltGesturesEnabled: false, - myLocationEnabled: false, - myLocationButtonEnabled: false, - markers: { - ...markers, - if (dotLocation != null && _dotMarkerBitmap != null) - Marker( - markerId: const MarkerId('dot'), - anchor: const Offset(.5, .5), - consumeTapEvents: true, - icon: BitmapDescriptor.fromBytes(_dotMarkerBitmap!), - position: _toServiceLatLng(dotLocation), - zIndex: 1, - ) - }, - // TODO TLAD [geotiff] may use ground overlay instead when this is fixed: https://github.com/flutter/flutter/issues/26479 - tileOverlays: { - if (overlayEntry != null && overlayEntry.canOverlay) - TileOverlay( - tileOverlayId: TileOverlayId(overlayEntry.id), - tileProvider: GmsGeoTiffTileProvider(overlayEntry), - transparency: 1 - overlayOpacity, + return LayoutBuilder( + builder: (context, constraints) { + _sizeNotifier.value = constraints.biggest; + return GoogleMap( + initialCameraPosition: CameraPosition( + bearing: -bounds.rotation, + target: _toServiceLatLng(bounds.projectedCenter), + zoom: bounds.zoom, ), + onMapCreated: (controller) async { + _serviceMapController = controller; + final zoom = await controller.getZoomLevel(); + await _updateVisibleRegion(zoom: zoom, rotation: bounds.rotation); + if (mounted) { + setState(() {}); + } + }, + // compass disabled to use provider agnostic controls + compassEnabled: false, + mapToolbarEnabled: false, + mapType: _toMapType(widget.style), + minMaxZoomPreference: MinMaxZoomPreference(widget.minZoom, widget.maxZoom), + rotateGesturesEnabled: true, + scrollGesturesEnabled: interactive, + // zoom controls disabled to use provider agnostic controls + zoomControlsEnabled: false, + zoomGesturesEnabled: interactive, + // lite mode disabled because it lacks camera animation + liteModeEnabled: false, + // tilt disabled to match leaflet + tiltGesturesEnabled: false, + myLocationEnabled: false, + myLocationButtonEnabled: false, + markers: { + ...markers, + if (dotLocation != null && _dotMarkerBitmap != null) + Marker( + markerId: const MarkerId('dot'), + anchor: const Offset(.5, .5), + consumeTapEvents: true, + icon: BitmapDescriptor.fromBytes(_dotMarkerBitmap!), + position: _toServiceLatLng(dotLocation), + zIndex: 1, + ) + }, + // TODO TLAD [geotiff] may use ground overlay instead when this is fixed: https://github.com/flutter/flutter/issues/26479 + tileOverlays: { + if (overlayEntry != null && overlayEntry.canOverlay) + TileOverlay( + tileOverlayId: TileOverlayId(overlayEntry.id), + tileProvider: GmsGeoTiffTileProvider(overlayEntry), + transparency: 1 - overlayOpacity, + ), + }, + onCameraMove: (position) => _updateVisibleRegion(zoom: position.zoom, rotation: -position.bearing), + onCameraIdle: _onIdle, + onTap: (position) => widget.onMapTap?.call(_fromServiceLatLng(position)), + ); }, - onCameraMove: (position) => _updateVisibleRegion(zoom: position.zoom, rotation: -position.bearing), - onCameraIdle: _onIdle, - onTap: (position) => widget.onMapTap?.call(_fromServiceLatLng(position)), ); }, ); @@ -229,6 +237,14 @@ class _EntryGoogleMapState extends State> with WidgetsBindi ); } + // sometimes the map does not properly update after changing the widget size, + // so we monitor the size and force refreshing after an arbitrary small delay + Future _onSizeChange() async { + await Future.delayed(const Duration(milliseconds: 100)); + debugPrint('refresh map for size=${_sizeNotifier.value}'); + await _serviceMapController?.setMapStyle(null); + } + void _onIdle() { if (!mounted) return; widget.controller?.notifyIdle(bounds);