Введение
Понадобилась мне как-то карта во флаттер-приложении. Гугл и Яндекс карты использовать не хотелось и оставалось только воспользоваться OSM. Карту сделать довольно просто, но и понадобилось добавить всплывающее окно при нажатии на маркер положения на карте. Перед тем как писать что-то самостоятельно решил поискать уже готовые решения и нашел плагин flutter_map_marker_popup.
Смотрим плагин
Зависимости которые потребуются:
dependencies:
flutter:
sdk: flutter
flutter_map: any
latlong2: any
flutter_map_marker_popup: any
Для начала добавим карту Flutter_map. Из важного тут - urlTemplate, который указывает на сервер OSM. Настройки в MapOptions передадим извне.
class MapPage extends StatefulWidget {
MapPage({super.key, required this.center, double? zoom}){
this.zoom = zoom ?? 9.0;
}
final LatLng center;
late final double zoom;
@override
State<MapPage> createState() => _MapPageState();
}
class _MapPageState extends State<MapPage> {
final urlTemplate = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Map page"),
),
body: FlutterMap(
mapController: MapController(),
options: MapOptions(
center: widget.center,
zoom: widget.zoom,
),
children: [
TileLayer(
urlTemplate: urlTemplate,
),
],
),
);
}
}
Дальше будем, например по долгому нажатию, создавать маркер на карте. Напишем функцию которая будет добавлять новый маркер в массив маркеров и передадим ее в MapOptions onLongPress: addMarker.
final List<Marker> _markers = [];
addMarker(tapPosition, point){
_markers.add(Marker(
point: point,
builder: (c) => const Icon(Icons.location_on, size: 40),
width: 40,
height: 40,));
}
Теперь эти маркеры можно стандартно отобразить с помощью слоя MarkerLayer(markers: _markers)
, но тогда не получится отслеживать нажатие по ним и отображать что-либо. Для этих задач в плагине flutter_map_marker_popup есть PopupMarkerLayerWidget
. Добавляем этот слой:
PopupMarkerLayerWidget(
options: PopupMarkerLayerOptions(
popupController: _popupLayerController,
markers: _markers,
markerRotateAlignment:
PopupMarkerLayerOptions.rotationAlignmentFor(AnchorAlign.top),
popupBuilder: (BuildContext context, Marker marker) =>
ExamplePopup(marker),
),
),
В этот слой передаются маркеры, контроллер, и способ создания попапа. ExamplePopup
- это виджет который будет появляться при нажатии на маркер. В нем и будут правила отображения всплывающего окна.
class ExamplePopup extends StatefulWidget {
final Marker marker;
const ExamplePopup(this.marker, {Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _ExamplePopupState();
}
class _ExamplePopupState extends State<ExamplePopup> {
int _currentIcon = 0;
@override
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: () => setState(() {
_currentIcon = (_currentIcon + 1) % 4;
}),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 20, right: 10),
child: Image.asset('assets/${_currentIcon+1}.png', width: 40, height: 40,),
),
_cardDescription(context),
],
),
),
);
}
Widget _cardDescription(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10),
child: Container(
constraints: const BoxConstraints(minWidth: 100, maxWidth: 200),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text(
'Popup for a marker!',
overflow: TextOverflow.fade,
softWrap: false,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 4.0)),
Text(
'Position: ${widget.marker.point.latitude}, ${widget.marker.point.longitude}',
style: const TextStyle(fontSize: 12.0),
),
Text(
'Marker size: ${widget.marker.width}, ${widget.marker.height}',
style: const TextStyle(fontSize: 12.0),
),
],
),
),
);
}
}
Примечание, для получения картинок из папки assets надо в pubspec.yml добавить настройку:
flutter:
assets:
- assets/
И вот у нас по нажатию на маркер всплывает окно с котиками.
Всем спасибо! Если интересно, есть телеграмм, заходите присаживайтесь).
Chelidonium
а для десктопных ещё один момент удобен и важен,
например скажем, - на карте с web-sdr чтобы жамкая
на ссылку во всплывшем окне получать переход
на новую страницу, иначе юзеру жать Ctrl каждый раз )