11import 'dart:math' ;
22
3+ import 'package:flutter/foundation.dart' ;
34import 'package:flutter/material.dart' ;
45import 'package:flutter/rendering.dart' ;
6+ import 'package:flutter/scheduler.dart' ;
57import 'package:flutter/widgets.dart' ;
68import 'package:flutter_map/flutter_map.dart' ;
79import 'package:latlong2/latlong.dart' ;
@@ -197,6 +199,8 @@ class RenderMapLayer extends RenderBox
197199 mapCamera.nonRotatedSize.y,
198200 );
199201
202+ final occupancyList = < Rect > [];
203+
200204 var child = firstChild;
201205 while (child != null ) {
202206 final childParentData = child.parentData! as _MapLayerParentData ;
@@ -205,11 +209,42 @@ class RenderMapLayer extends RenderBox
205209 // only render child if bounds are inside the viewport
206210 if (viewport.overlaps (childRect)) {
207211 context.paintChild (child, relativePixelPosition + offset);
212+
213+ if (childParentData.collider != null ) {
214+ final pos = _computeRelativeOffset (childParentData.offset & childParentData.collider! , childParentData.align! );
215+
216+ _handleCollision (pos, childParentData.collider! , occupancyList);
217+ }
208218 }
209219 child = childParentData.nextSibling;
210220 }
211221 }
212222
223+ Offset _computeRelativeOffset (Rect rect, Alignment align) {
224+ var globalPixelPosition = rect.topLeft;
225+ // apply rotation
226+ if (mapCamera.rotation != 0.0 ) {
227+ globalPixelPosition = mapCamera.rotatePoint (
228+ _pixelMapCenter,
229+ globalPixelPosition.toPoint (),
230+ counterRotation: false ,
231+ ).toOffset ();
232+ }
233+ // apply alignment
234+ return globalPixelPosition - align.alongSize (rect.size) - _nonRotatedPixelOrigin;
235+ }
236+
237+ void _handleCollision (Offset offset, BoxCollider collider, List <Rect > occupancyList) {
238+ final rect = offset & collider;
239+ if (occupancyList.any ((box) => box.overlaps (rect))) {
240+ collider.reportCollision (true , postFrame: true );
241+ }
242+ else {
243+ occupancyList.add (rect);
244+ collider.reportCollision (false , postFrame: true );
245+ }
246+ }
247+
213248 @override
214249 void debugFillProperties (DiagnosticPropertiesBuilder properties) {
215250 super .debugFillProperties (properties);
@@ -232,11 +267,14 @@ class MapLayerPositioned extends ParentDataWidget<_MapLayerParentData> {
232267
233268 final Alignment align;
234269
270+ final BoxCollider ? collider;
271+
235272 const MapLayerPositioned ({
236273 required this .position,
237274 required super .child,
238275 this .align = Alignment .center,
239276 this .size,
277+ this .collider,
240278 super .key,
241279 });
242280
@@ -263,6 +301,11 @@ class MapLayerPositioned extends ParentDataWidget<_MapLayerParentData> {
263301 parentData.align = align;
264302 targetParent.markNeedsPaint ();
265303 }
304+
305+ if (parentData.collider != collider) {
306+ parentData.collider = collider;
307+ targetParent.markNeedsPaint ();
308+ }
266309 }
267310
268311 @override
@@ -283,4 +326,41 @@ class _MapLayerParentData extends ContainerBoxParentData<RenderBox> {
283326 Size ? size;
284327
285328 Alignment ? align;
329+
330+ BoxCollider ? collider;
331+ }
332+
333+
334+
335+
336+
337+
338+
339+
340+
341+
342+
343+ class BoxCollider extends Size with ChangeNotifier implements ValueListenable <bool > {
344+ bool _collision = false ;
345+
346+ BoxCollider (super .width, super .height);
347+
348+ // ignore: avoid_positional_boolean_parameters
349+ void reportCollision (bool collision, { bool postFrame = false }) {
350+ if (collision != _collision) {
351+ _collision = collision;
352+
353+ if (postFrame) {
354+ SchedulerBinding .instance.addPostFrameCallback (
355+ (_) => notifyListeners (),
356+ );
357+ }
358+ else {
359+ notifyListeners ();
360+ }
361+ }
362+ }
363+
364+ @override
365+ bool get value => _collision;
286366}
0 commit comments