Skip to content

Commit

Permalink
Add MapEventNonRotatedSizeChange
Browse files Browse the repository at this point in the history
This new event is triggered when the map's non-rotated size is changed,
it is not called when the map is initialized. This will fix TileLayer
not loading new tiles when the map size changes.

In passing I made some other improvements:

 - Expose nonRotatedSize’s full type (CustomPoint<double>? instead of
   CustomPoint?) to avoid unnecessary type casts.
 - Improve the check for the constraints being ready before setting initial
   zoom/center based on MapOptions bounds.
 - Remove unnecessary setState in FlutterMapState’s emitMapEvent. The
   event emitting does not change the map's state and was causing double
   calls to setState in some code paths.
 - FlutterMapState tidy ups.
 - Removed the workaround for the initial map size being zero in TileLayer
   which caused tiles to not be loaded. The new MapEventNonRotatedSizeChange
   event removes the need for this workaround as during startup either:
     - The platform has already set flutter's resolution and thus all
       tiles are successfully loaded.
     - The platform has not set flutter's resolution but when it does it
       will cause LayoutBuilder to rebuild with the new size which will
       trigger a MapEventNonRotatedSizeChange event. This event will in
       turn trigger a tile load in TileLayer.
  • Loading branch information
rorystephenson committed May 1, 2023
1 parent 84b0029 commit 97586a1
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 172 deletions.
3 changes: 1 addition & 2 deletions lib/src/gestures/gestures.dart
Original file line number Diff line number Diff line change
Expand Up @@ -555,8 +555,7 @@ abstract class MapGestureMixin extends State<FlutterMap>

final direction = details.velocity.pixelsPerSecond / magnitude;
final distance = (Offset.zero &
Size(mapState.nonrotatedSize!.x as double,
mapState.nonrotatedSize!.y as double))
Size(mapState.nonrotatedSize!.x, mapState.nonrotatedSize!.y))
.shortestSide;

final flingOffset = _focalStartLocal - _lastFocalLocal;
Expand Down
65 changes: 65 additions & 0 deletions lib/src/gestures/map_events.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter_map/src/core/point.dart';
import 'package:latlong2/latlong.dart';

/// Event sources which are used to identify different types of
Expand All @@ -21,6 +22,7 @@ enum MapEventSource {
fitBounds,
custom,
scrollWheel,
nonRotatedSizeChange,
}

/// Base event class which is emitted by MapController instance, the event
Expand Down Expand Up @@ -59,6 +61,59 @@ abstract class MapEventWithMove extends MapEvent {
required super.center,
required super.zoom,
});

/// Returns a subclass of [MapEventWithMove] if the [source] belongs to a
/// movement event, otherwise returns null.
static MapEventWithMove? fromSource({
required LatLng targetCenter,
required double targetZoom,
required LatLng oldCenter,
required double oldZoom,
required bool hasGesture,
required MapEventSource source,
String? id,
}) {
switch (source) {
case MapEventSource.flingAnimationController:
return MapEventFlingAnimation(
center: oldCenter,
zoom: oldZoom,
targetCenter: targetCenter,
targetZoom: targetZoom,
source: source,
);
case MapEventSource.doubleTapZoomAnimationController:
return MapEventDoubleTapZoom(
center: oldCenter,
zoom: oldZoom,
targetCenter: targetCenter,
targetZoom: targetZoom,
source: source,
);
case MapEventSource.scrollWheel:
return MapEventScrollWheelZoom(
center: oldCenter,
zoom: oldZoom,
targetCenter: targetCenter,
targetZoom: targetZoom,
source: source,
);
case MapEventSource.onDrag:
case MapEventSource.onMultiFinger:
case MapEventSource.mapController:
case MapEventSource.custom:
return MapEventMove(
id: id,
center: oldCenter,
zoom: oldZoom,
targetCenter: targetCenter,
targetZoom: targetZoom,
source: source,
);
default:
return null;
}
}
}

/// Event which is fired when map is tapped
Expand Down Expand Up @@ -260,3 +315,13 @@ class MapEventRotateEnd extends MapEvent {
required super.zoom,
});
}

class MapEventNonRotatedSizeChange extends MapEvent {
const MapEventNonRotatedSizeChange({
required super.source,
required CustomPoint<double> previousNonRotatedSize,
required CustomPoint<double> nonRotatedSize,
required super.center,
required super.zoom,
});
}
30 changes: 1 addition & 29 deletions lib/src/layer/tile_layer/tile_layer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,7 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {
);
}

if (reloadTiles) {
_tryWaitForSizeToBeInitialized(
mapState,
() => _loadAndPruneInVisibleBounds(mapState),
);
}
if (reloadTiles) _loadAndPruneInVisibleBounds(mapState);

_initializedFromMapState = true;
}
Expand Down Expand Up @@ -658,27 +653,4 @@ class _TileLayerState extends State<TileLayer> with TickerProviderStateMixin {

bool _outsideZoomLimits(num zoom) =>
zoom < widget.minZoom || zoom > widget.maxZoom;

// A workaround for the fact that FlutterMapState size initialization has a
// race condition where sometimes the size is set to CustomPoint(0,0) before
// it is set to the correct value. When this occurs, code that relies on the
// visible bounds will not work correctly. Sometimes it requires more than
// one postFrameCallback to get a non zero size.
void _tryWaitForSizeToBeInitialized(
FlutterMapState mapState,
VoidCallback callback, {
int retries = 3,
}) {
if (retries >= 0 && mapState.size == const CustomPoint(0, 0)) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_tryWaitForSizeToBeInitialized(
mapState,
callback,
retries: retries - 1,
);
});
} else {
callback();
}
}
}
Loading

0 comments on commit 97586a1

Please sign in to comment.