I have an App developed using Flutter.
I use
return Scaffold(
body: Stack(
children: [
FlutterMap(...),
Positioned(
bottom: 20,
right: 0,
child: Container(
color: Colors.white,
child: getPoints(), // just returning a Row with some Buttons to select a Point
),
),
]
)
);
Widget getPoints() {
return Row(
children: [
TextButton( .... ),
...
]);
}
This displays the Container with some Buttons over the FlutterMap. That's working fine.
But now: The user can zoom and drag the map and he can select some 'Points' with Buttons shown within that Container. And now I like to move the selected 'Points' into the visible part of the map. I'm able to move the 'Point' into the map if it's outside of the map, but maybe the 'Point' is behind the Container and not outside of the map. Now I like to check the geo-positions hidden by the Container. But how can I do that?
here an screenshot
I didn't find a solution or even a similar question somewhere.
I have an App developed using Flutter.
I use
return Scaffold(
body: Stack(
children: [
FlutterMap(...),
Positioned(
bottom: 20,
right: 0,
child: Container(
color: Colors.white,
child: getPoints(), // just returning a Row with some Buttons to select a Point
),
),
]
)
);
Widget getPoints() {
return Row(
children: [
TextButton( .... ),
...
]);
}
This displays the Container with some Buttons over the FlutterMap. That's working fine.
But now: The user can zoom and drag the map and he can select some 'Points' with Buttons shown within that Container. And now I like to move the selected 'Points' into the visible part of the map. I'm able to move the 'Point' into the map if it's outside of the map, but maybe the 'Point' is behind the Container and not outside of the map. Now I like to check the geo-positions hidden by the Container. But how can I do that?
here an screenshot
I didn't find a solution or even a similar question somewhere.
Share Improve this question asked 2 days ago jpganizerjpganizer 33 bronze badges New contributor jpganizer is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.1 Answer
Reset to default 0Use a GlobalKey on both the map and your Container to measure their positions/sizes on screen. Use the latLngToScreenPoint method of the FlutterMapController to get the screen coordinates. Check if the user’s point or bounding box overlaps with the container.
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong2.dart';
import 'dart:math' as math;
class MapWithContainer extends StatefulWidget {
const MapWithContainer({Key? key}) : super(key: key);
@override
_MapWithContainerState createState() => _MapWithContainerState();
}
class _MapWithContainerState extends State<MapWithContainer> {
final MapController _mapController = MapController();
final GlobalKey _containerKey = GlobalKey(); //-> Key for the Container
LatLng? _pointToCheck; //-> LatLng to check if it's hidden
@override
void initState() {
super.initState();
//-> Initialize the point to check.
_pointToCheck = LatLng(48.8566, 2.3522); //-> Example Paris
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
FlutterMap(
mapController: _mapController,
options: MapOptions(
center: LatLng(48.8566, 2.3522),
zoom: 8.0,
),
children: [
TileLayer(
urlTemplate: 'https://{s}.tile.openstreetmap./{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
),
if (_pointToCheck != null)
MarkerLayer(
markers: [
Marker(
width: 20.0,
height: 20.0,
point: _pointToCheck!,
builder: (ctx) => Container(
decoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
),
),
],
),
],
),
Positioned(
bottom: 20,
right: 0,
child: Container(
key: _containerKey, //-> Assign the key
color: Colors.white,
child: getPoints(), //-> just returning
),
),
Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
onPressed: () {
//-> Check if point is obscured
bool isHidden = isLatLngObscured(_pointToCheck);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Point Obscured?'),
content: Text('The point is obscured: $isHidden'),
actions: <Widget>[
TextButton(
child: const Text('Close'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
},
child: const Text("Check if point is obscured"),
),
),
),
],
),
);
}
Widget getPoints() {
return Row(
children: [
TextButton(
child: const Text('Point A'),
onPressed: () {
setState(() {
_pointToCheck = LatLng(48.8566, 2.3522); //-> Paris
_movePointIntoView();
});
},
),
TextButton(
child: const Text('Point B'),
onPressed: () {
setState(() {
_pointToCheck = LatLng(43.6047, 1.4442); //-> Toulouse
_movePointIntoView();
});
},
),
TextButton(
child: const Text('Point C'),
onPressed: () {
setState(() {
_pointToCheck = LatLng(45.7597, 4.8422); //-> Lyon
_movePointIntoView();
});
},
),
],
);
}
bool isLatLngObscured(LatLng? latLng) {
if (latLng == null) return false;
final RenderBox containerBox =
_containerKey.currentContext?.findRenderObject() as RenderBox;
final Size containerSize = containerBox.size;
final Offset containerPosition = containerBox.localToGlobal(Offset.zero);
//-> Convert LatLng to screen coordinates
final math.Point<double>? screenPoint =
_mapController.latLngToScreenPoint(latLng);
if (screenPoint == null) {
return false;
}
//-> Check if the screen point is within the container's bounds
return (screenPoint.x >= containerPosition.dx &&
screenPoint.x <= containerPosition.dx + containerSize.width &&
screenPoint.y >= containerPosition.dy &&
screenPoint.y <= containerPosition.dy + containerSize.height);
}
void _movePointIntoView() {
if (_pointToCheck != null && isLatLngObscured(_pointToCheck)) {
final RenderBox containerBox =
_containerKey.currentContext?.findRenderObject() as RenderBox;
final Size containerSize = containerBox.size;
final double latOffset = containerSize.height / 200.0;
final LatLng newCenter =
LatLng(_pointToCheck!.latitude + latOffset, _pointToCheck!.longitude);
//-> Move the map to the new center.
_mapController.move(newCenter, _mapController.zoom);
}
}
}