Попап на флаттер карте или flutter_map_marker_popup
Tags: flutter, osm, map
Published: 2022-09-21 08:55:19

#Введение#
Понадобилась мне как-то карта во флаттер-приложении. Гугл и яндекс карты использовать не хотелось и оставалось только воспользоваться OSM. Ну и понадобилось добавить всплывающее окно при нажатии на маркер положения на карте, нашел как это делать для гугла и яндекса, а для flutter_mup не сразу нашел. Но оказалось есть плагин flutter_map_marker_popup.
#Смотрим плагин#
Зависимости укажем такие:
```
dependencies:
  flutter:
    sdk: flutter
  flutter_map: any
  latlong2: any
  flutter_map_marker_popup: any
```

Для начала нам потребуется карта Flutter_map, на которой уже будем располагать наши маркеры. Добавим ее 
```
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/
```
И вот раз, и у нас по нажатию на маркер всплывает окно с котиками.

<img width="100%" style="width:100%" src="https://media.giphy.com/media/5bEK732Q182EAkn5cd/giphy.gif">

Всем спасибо! Если интересно, есть [телеграмм](https://t.me/avtarasov210), заходите присаживайтесь).