Всплывающие окна на флаттер карте или flutter_map_marker_popup

от автора

Введение

Понадобилась мне как-то карта во флаттер-приложении. Гугл и Яндекс карты использовать не хотелось и оставалось только воспользоваться 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/

И вот у нас по нажатию на маркер всплывает окно с котиками.

Всем спасибо! Если интересно, есть телеграмм, заходите присаживайтесь).


ссылка на оригинал статьи https://habr.com/ru/post/689578/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *