#241 improved google map refresh on size change
This commit is contained in:
parent
fecfa45a29
commit
406e99b13f
2 changed files with 69 additions and 55 deletions
|
@ -429,8 +429,6 @@ class _ContentState extends State<_Content> with SingleTickerProviderStateMixin
|
||||||
|
|
||||||
void _toggleOverlay() => _overlayVisible.value = !_overlayVisible.value;
|
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<void> _onOverlayVisibleChange({bool animate = true}) async {
|
Future<void> _onOverlayVisibleChange({bool animate = true}) async {
|
||||||
if (_overlayVisible.value) {
|
if (_overlayVisible.value) {
|
||||||
if (animate) {
|
if (animate) {
|
||||||
|
|
|
@ -57,6 +57,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
final Map<MarkerKey<T>, Uint8List> _markerBitmaps = {};
|
final Map<MarkerKey<T>, Uint8List> _markerBitmaps = {};
|
||||||
final StreamController<MarkerKey<T>> _markerBitmapReadyStreamController = StreamController.broadcast();
|
final StreamController<MarkerKey<T>> _markerBitmapReadyStreamController = StreamController.broadcast();
|
||||||
Uint8List? _dotMarkerBitmap;
|
Uint8List? _dotMarkerBitmap;
|
||||||
|
final ValueNotifier<Size> _sizeNotifier = ValueNotifier(Size.zero);
|
||||||
|
|
||||||
ValueNotifier<ZoomedBounds> get boundsNotifier => widget.boundsNotifier;
|
ValueNotifier<ZoomedBounds> get boundsNotifier => widget.boundsNotifier;
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
_sizeNotifier.addListener(_onSizeChange);
|
||||||
_registerWidget(widget);
|
_registerWidget(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +85,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
_unregisterWidget(widget);
|
_unregisterWidget(widget);
|
||||||
_serviceMapController?.dispose();
|
_serviceMapController?.dispose();
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
_sizeNotifier.removeListener(_onSizeChange);
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +112,7 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.resumed:
|
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
|
// cf https://github.com/flutter/flutter/issues/40284
|
||||||
_serviceMapController?.setMapStyle(null);
|
_serviceMapController?.setMapStyle(null);
|
||||||
break;
|
break;
|
||||||
|
@ -166,60 +169,65 @@ class _EntryGoogleMapState<T> extends State<EntryGoogleMap<T>> with WidgetsBindi
|
||||||
return ValueListenableBuilder<double>(
|
return ValueListenableBuilder<double>(
|
||||||
valueListenable: widget.overlayOpacityNotifier ?? ValueNotifier(1),
|
valueListenable: widget.overlayOpacityNotifier ?? ValueNotifier(1),
|
||||||
builder: (context, overlayOpacity, child) {
|
builder: (context, overlayOpacity, child) {
|
||||||
return GoogleMap(
|
return LayoutBuilder(
|
||||||
initialCameraPosition: CameraPosition(
|
builder: (context, constraints) {
|
||||||
bearing: -bounds.rotation,
|
_sizeNotifier.value = constraints.biggest;
|
||||||
target: _toServiceLatLng(bounds.projectedCenter),
|
return GoogleMap(
|
||||||
zoom: bounds.zoom,
|
initialCameraPosition: CameraPosition(
|
||||||
),
|
bearing: -bounds.rotation,
|
||||||
onMapCreated: (controller) async {
|
target: _toServiceLatLng(bounds.projectedCenter),
|
||||||
_serviceMapController = controller;
|
zoom: bounds.zoom,
|
||||||
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,
|
|
||||||
),
|
),
|
||||||
|
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<T> extends State<EntryGoogleMap<T>> 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<void> _onSizeChange() async {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
debugPrint('refresh map for size=${_sizeNotifier.value}');
|
||||||
|
await _serviceMapController?.setMapStyle(null);
|
||||||
|
}
|
||||||
|
|
||||||
void _onIdle() {
|
void _onIdle() {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
widget.controller?.notifyIdle(bounds);
|
widget.controller?.notifyIdle(bounds);
|
||||||
|
|
Loading…
Reference in a new issue