fix: stop syncing gesture positions back to mapProvider
Removed the updateCamera() call from onPositionChanged. Previously, every gesture-driven pan/zoom frame updated the provider state, which triggered ref.listen to call _mapController.move() redundantly. This caused flutter_map's TileLayer to cancel in-flight tile loads on every frame — producing partially-rendered maps and crashes when zooming out during tile loading. The ref.listen now only fires for programmatic changes (locateUser, zoomIn/zoomOut), which are infrequent single-shot moves. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
578d2d24ed
commit
a3aaf1b6de
1 changed files with 11 additions and 17 deletions
|
|
@ -41,19 +41,13 @@ class _MapScreenState extends ConsumerState<MapScreen> {
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
final styleAsync = ref.watch(mapStyleProvider(apiClient.baseUrl));
|
final styleAsync = ref.watch(mapStyleProvider(apiClient.baseUrl));
|
||||||
|
|
||||||
// Listen for zoom/center changes from the provider and move the map.
|
// Move the map only for programmatic state changes (locateUser,
|
||||||
// Skip the move if the map controller is already at the target position
|
// zoomIn/zoomOut). Gesture-driven pans no longer call updateCamera(),
|
||||||
// (meaning the state change came from a user gesture via onPositionChanged).
|
// so this listener only fires for intentional moves and won't interfere
|
||||||
// Without this guard, every gesture-driven pan calls _mapController.move()
|
// with the TileLayer's in-flight tile loads.
|
||||||
// with the position the map is already at, which triggers a tile
|
|
||||||
// recalculation that cancels in-flight tile loads and produces a
|
|
||||||
// partially-rendered (diagonal) map.
|
|
||||||
ref.listen<MapState>(mapProvider, (previous, next) {
|
ref.listen<MapState>(mapProvider, (previous, next) {
|
||||||
if (previous?.center != next.center || previous?.zoom != next.zoom) {
|
if (previous?.center != next.center || previous?.zoom != next.zoom) {
|
||||||
final camera = _mapController.camera;
|
_mapController.move(next.center, next.zoom);
|
||||||
if (camera.center != next.center || camera.zoom != next.zoom) {
|
|
||||||
_mapController.move(next.center, next.zoom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -69,12 +63,12 @@ class _MapScreenState extends ConsumerState<MapScreen> {
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
maxZoom: 18,
|
maxZoom: 18,
|
||||||
onPositionChanged: (position, hasGesture) {
|
onPositionChanged: (position, hasGesture) {
|
||||||
if (hasGesture) {
|
// Intentionally not syncing gesture-driven position changes
|
||||||
ref.read(mapProvider.notifier).updateCamera(
|
// back to the provider. Doing so caused ref.listen to call
|
||||||
position.center,
|
// _mapController.move() on every pan/zoom frame, which made
|
||||||
position.zoom,
|
// flutter_map's TileLayer cancel in-flight tile loads —
|
||||||
);
|
// producing a partially-rendered (diagonal) map and crashes
|
||||||
}
|
// when zooming out during tile loading.
|
||||||
},
|
},
|
||||||
onTap: (tapPosition, point) {
|
onTap: (tapPosition, point) {
|
||||||
ref.read(mapProvider.notifier).clearSelectedPlace();
|
ref.read(mapProvider.notifier).clearSelectedPlace();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue