Как на карту OSM вывести все маркеры из API? Dart
Я делаю вывод маркеров из АПИ на карту: для это создал массив с Маркерами и отдельный массив с остановками, из массива с остановками я forEach-ем вытаскиваю все координаты и складываю в массив со всеми маркерами и пытаюсь запустить все точки на карту. Падение в ошибку пофикшено. спасибо за подсказку в комментариях.
Теперь проблема следующая (довольно глупая проблема, не понимаю. что оно не так работает):
Точки отображаются, но не там, где мне нужно. То есть мне нужно, чтобы точки координаты которых - Вологодская область, отображались именно в ней, а не в Казахстане :)
Ошибки в запросе быть не может, иначе бы не прилетал ответ от сервака в стэктрейс. Думаю, что как-то неправильно задаю саму карту, но я уж три часа ее кручу-верчу, но все никак не могу сообразить, что не так делаю. Сейчас код выглядит вот
class _MapState extends State<Map> {
@override
void initState() {
futureStops = fetchStops();
super.initState();
}
List<Stop> listStops = [];
Future<List<Stop>> futureStops;
List<Marker> allMarkers = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder<List<Stop>>(
future: futureStops,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
listStops = snapshot.data;
print('xdecf');
listStops.forEach((Stops) {
print('bedcbjhefc');
allMarkers = listStops
.map(
(e) => Marker(
width: 0.2,
height: 0.2,
point: latLong.LatLng(e.stLat, e.stLat),
builder: (_) => Icon(
Icons.person_pin,
color: Colors.red,
)),
)
.take(3)
.toList();
print(allMarkers);
print('object');
});
}
return FlutterMap(
options: MapOptions(
center: latLong.LatLng(координаты),
zoom: 13.0,
),
layers: [
TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
MarkerLayerOptions(markers: allMarkers),
]);
return Center(child: CircularProgressIndicator());
}),
Ответы (2 шт):
Не хватает проверки на null
listStops!.forEach(
// либо
if(listStops != null) {
Решил эту задачу: было странно, что не работало вчера, потому что вроде как все правильно сделал. Здесь оставляю ответ, на случай если кому-нибудь нужно будет готовое решение этой проблемы.
Задача стояла такая: использовать исключительно опенсорс и сверху сделать окно с дополнительной инфой про маркер (местоположение, название и т.д). Также всё то огромное количество точек, которое мне нужно вывести, было решено объединить в кластеры, потому что такое огромное количество точек карта бы проглотить не смогла.
Использовал вот эти пакеты и с такой версией sdk:
sdk: ">=2.12.0 <3.0.0"
flutter_map_marker_popup: ^1.0.0
flutter_map: ^0.14.0
flutter_map_marker_cluster: ^0.4.0
latlong2: ^0.8.1
У меня написано не на null-safety.
Поэтому для решения моей проблемы создал два массива: массив с маркерами и массив с моими точками/координатами, после этого использовал простой future builder (наверное есть способ элегантнее, но я сам до него не додумался) и два метода forEach и map. Чтобы они постоянно не валились в ошибку, проверяю, есть ли вообще что-нибудь внутри FutureBuilder.
class MapPage extends StatefulWidget {
const MapPage({Key key}) : super(key: key);
@override
_MapPageState createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
final PopupController _popupController = PopupController();
@override
void initState() {
futureStops = fetchStops();
super.initState();
}
Future<List<Stop>> futureStops;
List<Marker> allMarkers = [];
List<Stop> listStops = [];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: FutureBuilder<List<Stop>>(
future: fetchStops(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
listStops = snapshot.data;
print('POINT 1');
listStops.forEach((element) {
allMarkers = listStops
.map((e) =>
Marker(
point: latLong.LatLng(e.stLat, e.stLong),
builder: (_) => Icon(Icons.person_pin)))
.toList(growable: true);
});
}
return FlutterMap(
options: new MapOptions(
center: latLong.LatLng(ваши координаты),
zoom: 13,
plugins: [
MarkerClusterPlugin(),
],
//HERE IS ON TAP OPTIONS
),
layers: [
TileLayerOptions(
urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
),
MarkerClusterLayerOptions(
maxClusterRadius: 120,
size: Size(40, 40),
markers: allMarkers,
polygonOptions: PolygonOptions(
borderColor: Colors.blueAccent,
color: Colors.black12,
borderStrokeWidth: 3),
popupOptions: PopupOptions(
popupSnap: PopupSnap.mapTop,
popupController: _popupController,
popupBuilder: (_, allMarkers) => Container(
width: 200,
height: 100,
color: Colors.white,
child: GestureDetector(
onTap: () => debugPrint('on marker tapped'),
child: Text('Container popup for marker at ${allMarkers.point}'),
),
)
),
builder: (context, markers) {
return FloatingActionButton(
child: Text(markers.length.toString()),
onPressed: null,
);
},
),
],
);
}
));
}
}
Может способ и не самый эффективный с точки зрения производительности (карта загрузилась за 3 секунды, прорисовав потом все кластеры почти моментально, то есть ну секунд 5-7 на это все дело ушло), но рабочий. Опять-таки повторюсь, что сам пока не додумался как сделать лучше. Тут оставляю ответ на случай, если кому-нибудь понадобится когда-то :)