{"id":336397,"date":"2022-07-31T15:00:18","date_gmt":"2022-07-31T15:00:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=336397"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=336397","title":{"rendered":"<span>\u041c\u0430\u0440\u043a\u0435\u0440\u044b \u043d\u0430 Google Maps \u0432\u043e Flutter: \u043e\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u043a \u0441\u043b\u043e\u0436\u043d\u043e\u043c\u0443<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042f \u2014 \u0422\u0438\u043c, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0413\u0443\u0434\u0438\u0442\u0432\u043e\u0440\u043a\u0441. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u044b \u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0433\u0438\u0434 \u043f\u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430\u043c. \u041d\u0430\u043c \u0431\u044b\u043b\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u043a\u0430\u0440\u0442\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u043b\u0430\u0441\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430\u0445, \u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u0431\u044b \u043e\u0442\u043c\u0435\u0447\u0430\u0442\u044c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0432\u0448\u0438\u0435\u0441\u044f. \u042f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043e Flutter \u0441 \u043a\u0430\u0440\u0442\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u043c\u0430\u0440\u043a\u0435\u0440\u0430\u043c\u0438. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430 \u2014 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0430.<\/p>\n<h2>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b  <\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u0430\u0440\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u044b \u044f \u0432\u044b\u0431\u0440\u0430\u043b Google Maps. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0438\u043c \u0432\u043e Flutter \u0435\u0441\u0442\u044c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/pub.dev\/packages\/google_maps_flutter\" rel=\"noopener noreferrer nofollow\">google_maps_flutter<\/a>. \u041f\u0430\u043a\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0444\u0430\u0439\u043b <strong>pubspec.yaml<\/strong>:<\/p>\n<pre><code class=\"yaml\">dependencies:   ...   google_maps_flutter: ^2.1.8   ...<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u0430\u0440\u0442\u0430\u043c, \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f API-\u043a\u043b\u044e\u0447: \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 <a href=\"https:\/\/developers.google.com\/maps\/documentation\/android-sdk\/get-api-key\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> Maps SDK. \u0414\u043b\u044f Android \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043b\u044e\u0447 \u0432 \u0444\u0430\u0439\u043b <strong>android\/app\/src\/main\/AndroidManifest.xml<\/strong>:<\/p>\n<pre><code class=\"xml\">&lt;manifest ...    &lt;application ...         &lt;meta-data android:name=\"com.google.android.geo.API_KEY\"                    android:value=\"API-\u041a\u041b\u042e\u0427\"\/><\/code><\/pre>\n<p> \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u0441 \u043a\u0430\u0440\u0442\u043e\u0439 \u0432 \u0444\u0430\u0439\u043b <strong>main.dart<\/strong>:<\/p>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart'; import 'package:flutter\/services.dart'; import 'package:google_maps_flutter\/google_maps_flutter.dart';  void main() => runApp(const MyApp());  class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return const MaterialApp(       home: Scaffold(         body: CustomMap(),       ),     );   } }  class CustomMap extends StatefulWidget {   const CustomMap({Key? key}) : super(key: key);    @override   _CustomMapState createState() => _CustomMapState(); }  class _CustomMapState extends State&lt;CustomMap> {   GoogleMapController? _controller;   static const LatLng _center = LatLng(48.864716, 2.349014);    void _onMapCreated(GoogleMapController controller) {     setState(() {       _controller = controller;     });      rootBundle.loadString('assets\/map_style.json').then((mapStyle) {       _controller?.setMapStyle(mapStyle);     });   }    @override   Widget build(BuildContext context) {     return GoogleMap(       onMapCreated: _onMapCreated,       initialCameraPosition: const CameraPosition(         target: _center,         zoom: 12,       ),     );   } }<\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430:<\/p>\n<ul>\n<li>\n<p>\u043c\u0435\u0442\u043e\u0434 <code>_onMapCreated<\/code>: \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043a\u0430\u0440\u0442\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>GoogleMapController<\/code>,<\/p>\n<\/li>\n<li>\n<p>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>initialCameraPosition<\/code>: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b,<\/p>\n<\/li>\n<li>\n<p><code>GoogleMapController<\/code>: \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0440\u0442\u043e\u0439 \u2014 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439, \u0437\u0443\u043c\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u0430\u0440\u0442\u0430 \u0431\u044b\u043b\u0430 \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435, \u044f \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043b \u0441\u0442\u0438\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>assets\/map_style.json<\/strong>. \u0421\u0442\u0438\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443 \u0443\u0434\u043e\u0431\u043d\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c <a href=\"http:\/\/mapstyle.withgoogle.com\" rel=\"noopener noreferrer nofollow\">mapstyle.withgoogle.com<\/a>. \u0422\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0440\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5c8\/9fc\/52f\/5c89fc52ffd59ad6472e7633ac8fa8e4.png\" width=\"1080\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5c8\/9fc\/52f\/5c89fc52ffd59ad6472e7633ac8fa8e4.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/init-gm\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/init-gm<\/a><\/p>\n<h3>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b  <\/h3>\n<p>\u041d\u0430 \u043a\u0430\u0440\u0442\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b: \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0438, \u043a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u043e\u0432 \u2014 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>datasource.dart<\/strong><\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>_upsertMarker<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043c\u0430\u0440\u043a\u0435\u0440\u044b:<\/p>\n<pre><code class=\"dart\">void _upsertMarker(Place place) {     setState(() {       _markers.add(Marker(         markerId: MarkerId(place.id),         position: place.location,         infoWindow: InfoWindow(           title: place.name,           snippet:               [...place.occasions, ...place.vibes, ...place.budget].join(\", \"),         ),         icon: BitmapDescriptor.defaultMarker,       ));     });   }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>infoWindow<\/code> \u043f\u043e \u0442\u0430\u043f\u0443 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0438\u043d \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0435, \u0430 \u043d\u0430 \u043a\u0430\u0440\u0442\u0443 \u043c\u0430\u0440\u043a\u0435\u0440\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 <code>markers<\/code> \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <code>GoogleMap<\/code>:<\/p>\n<pre><code class=\"dart\">void _mapPlacesToMarkers() {   for (final place in _places) {     _upsertMarker(place);   } } ... @override initState() {   super.initState();   _mapPlacesToMarkers(); }  @override Widget build(BuildContext context) {   return GoogleMap(     onMapCreated: _onMapCreated,     initialCameraPosition: const CameraPosition(       target: _center,       zoom: 12,     ),     markers: _markers,   ); }<\/code><\/pre>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5e6\/2c3\/a3a\/5e62c3a3a7db9427d10c9d8630bdb394.png\" width=\"1080\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5e6\/2c3\/a3a\/5e62c3a3a7db9427d10c9d8630bdb394.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/default-markers\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/default-markers<\/a><\/p>\n<h3>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e \u0442\u0430\u043f\u0443  <\/h3>\n<p>\u041d\u043e \u043f\u0438\u043d\u0430 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0441 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0435\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0435\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 \u0432 <code>_CustomMapState<\/code>. \u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0442\u0430\u043f\u0443 \u043d\u0430 \u043c\u0430\u0440\u043a\u0435\u0440 (\u043c\u0435\u0442\u043e\u0434 <code>_selectPlace<\/code>), \u0430 \u0438\u0441\u0447\u0435\u0437\u0430\u0442\u044c \u043f\u043e \u0442\u0430\u043f\u0443 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u0430 \u043d\u0435\u0442 (\u043c\u0435\u0442\u043e\u0434 <code>_unselectPlace<\/code>). \u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <code>Positioned<\/code>:<\/p>\n<pre><code class=\"dart\">class _CustomMapState extends State&lt;CustomMap> {   ...   final List&lt;Place> _places = places;   Place? _selectedPlace;      void _unselectPlace() {     setState(() {       _selectedPlace = null;     });   }      void _selectPlace(Place place) {     setState(() {       _selectedPlace = place;     });   }    void _upsertMarker(Place place) {     setState(() {       _markers.add(Marker(         ...         onTap: () => _selectPlace(place),         ...       ));     });   }   ...     @override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         GoogleMap(           ...           ),           markers: _markers,           onTap: (_) => _unselectPlace(),         ),         if (_selectedPlace != null)           Positioned(             bottom: 76,             child: PhysicalModel(               color: Colors.black,               shadowColor: Colors.black.withOpacity(0.6),               borderRadius: BorderRadius.circular(12),               elevation: 12,               child: Container(                 decoration: const BoxDecoration(                   color: Colors.white,                   borderRadius: BorderRadius.all(Radius.circular(12)),                 ),                 child: MapPlaceCard(                   place: _selectedPlace!,                 ),               ),             ),           ),       ],     );   }<\/code><\/pre>\n<p> \u0422\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0440\u0442\u0430 \u2014 \u0441 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430\u043c\u0438:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6c1\/d86\/e80\/6c1d86e80fe68c7515bec335d1de8093.png\" width=\"1080\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6c1\/d86\/e80\/6c1d86e80fe68c7515bec335d1de8093.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/cards-on-tap\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/cards-on-tap<\/a>  <\/p>\n<h3>\u041c\u0435\u043d\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u044b  <\/h3>\n<p>\u0411\u044b\u043b\u043e \u0431\u044b \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u043e\u0442\u043c\u0435\u0447\u0430\u0442\u044c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0432\u0448\u0438\u0435\u0441\u044f \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u044b, \u0438 \u043c\u0430\u0440\u043a\u0435\u0440 \u0431\u044b \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u043d\u044f\u043b\u0441\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0438\u043a\u043e\u043d\u043a\u0438:  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/606\/db5\/ebf\/606db5ebf0450e6440cd24f8055d75c3.png\" width=\"1200\" height=\"234\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/606\/db5\/ebf\/606db5ebf0450e6440cd24f8055d75c3.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u041c\u0430\u0440\u043a\u0435\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>_upsertMarker<\/code>:<\/p>\n<pre><code class=\"dart\">Future&lt;void> _upsertMarker(Place place) async {     final selectedPrefix = place.id == _selectedPlace?.id ? \"selected_\" : \"\";     final favoritePostfix =         _likedPlaceIds.contains(place.id) ? \"_favorite\" : \"\";      final icon = await BitmapDescriptor.fromAssetImage(       const ImageConfiguration(),       \"assets\/icons\/${selectedPrefix}map_place$favoritePostfix.png\",     );      setState(() {       _markers.add(Marker(         markerId: MarkerId(place.id),         position: place.location,         onTap: () => _selectPlace(place),         icon: icon,       ));     });   }<\/code><\/pre>\n<p>\u0421\u0435\u0440\u0434\u0435\u0447\u043a\u043e-\u043b\u0430\u0439\u043a \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>_likeTapHandler<\/code>:<\/p>\n<pre><code class=\"dart\">void _likeTapHandler() async {     if (_selectedPlace == null) return;     setState(() {       if (_likedPlaceIds.contains(_selectedPlace!.id)) {         _likedPlaceIds.removeAt(_likedPlaceIds.indexOf(_selectedPlace!.id));       } else {         _likedPlaceIds.add(_selectedPlace!.id);       }     });      _upsertMarker(_selectedPlace!);   }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 <code>MapPlaceCard<\/code>:<\/p>\n<pre><code class=\"dart\">@override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         ...         if (_selectedPlace != null)           Positioned(             ...             child: PhysicalModel(               ...               child: Container(                 ...                 child: MapPlaceCard(                   place: _selectedPlace!,                   isLiked: _likedPlaceIds.contains(_selectedPlace!.id),                   likeTapHandler: _likeTapHandler,                 ),               ),             ),           ),       ],     );   }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0438\u043a\u043e\u043d\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>_unselectPlace<\/code> \u2014 \u043e\u043d \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u044b\u0431\u043e\u0440 \u0441 \u043c\u0435\u0441\u0442\u0430 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0438\u043a\u043e\u043d\u043a\u0443:<\/p>\n<pre><code class=\"dart\">class _CustomMapState extends State&lt;CustomMap> {   ...   Future&lt;void> _unselectPlace() async {     if (_selectedPlace == null) return;      final place = _selectedPlace;     setState(() {       _selectedPlace = null;     });      await _upsertMarker(place!);   }    Future&lt;void> _selectPlace(Place place) async {     await _unselectPlace();      setState(() {       _selectedPlace = place;     });      await _upsertMarker(place);   }   ...   @override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         GoogleMap(           ...           ),           markers: _markers,           onTap: (_) => _unselectPlace(),         ),         if (_selectedPlace != null)           Positioned(             bottom: 76,             child: PhysicalModel(               color: Colors.black,               shadowColor: Colors.black.withOpacity(0.6),               borderRadius: BorderRadius.circular(12),               elevation: 12,               child: Container(                 decoration: const BoxDecoration(                   color: Colors.white,                   borderRadius: BorderRadius.all(Radius.circular(12)),                 ),                 child: MapPlaceCard(                   place: _selectedPlace!,                   isLiked: _likedPlaceIds.contains(_selectedPlace!.id),                   likeTapHandler: _likeTapHandler,                 ),               ),             ),           ),       ],     );   } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0430 \u043a\u0430\u0440\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/57f\/417\/850\/57f417850f253e0892ac3875db406c76.png\" alt=\"\u0421\u043b\u0435\u0432\u0430 \u2014 \u043d\u0435\u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439\" title=\"\u0421\u043b\u0435\u0432\u0430 \u2014 \u043d\u0435\u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439\" width=\"2180\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/57f\/417\/850\/57f417850f253e0892ac3875db406c76.png\"\/><figcaption>\u0421\u043b\u0435\u0432\u0430 \u2014 \u043d\u0435\u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439<\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/different-icons\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/different-icons<\/a><\/p>\n<h3>\u041d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b<\/h3>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u2014 \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430 \u0431\u044b\u043b\u043e \u0432\u0438\u0434\u043d\u043e \u0432\u0441\u0435\u0433\u0434\u0430, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0442\u0430\u043f\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u0430 <strong>utils\/custom_marker_drawer.dart<\/strong><\/p>\n<pre><code class=\"dart\">... class CustomMarkerDrawer {   ...   Future&lt;CustomMarker> createCustomMarkerBitmap({     ...   }) async {     ...     PictureRecorder recorder = PictureRecorder();     Canvas canvas = Canvas(       recorder,       Rect.fromLTWH(         0,         0,         scaledCanvasWidth,         scaledCanvasHeight,       ),     );     ...     Picture picture = recorder.endRecording();     ByteData? pngBytes = await (await picture.toImage(       scaledCanvasWidth.toInt(),       scaledCanvasHeight.toInt(),     ))         .toByteData(format: ImageByteFormat.png);      Uint8List data = Uint8List.view(pngBytes!.buffer);      final marker = BitmapDescriptor.fromBytes(data);     const double anchorDx = .5;     final anchorDy = imageHeight \/ scaledCanvasHeight;      return CustomMarker(marker: marker, anchorDx: anchorDx, anchorDy: anchorDy);   }   ... }<\/code><\/pre>\n<p>\u041c\u044b \u0440\u0438\u0441\u0443\u0435\u043c \u043d\u0430 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u043c <code>Canvas<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 <code>Picture<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>PictureRecorder<\/code>. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u0432 <code>Uint8List<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a 8-\u0431\u0438\u0442\u043d\u044b\u0445 \u0431\u0435\u0437\u0437\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u0446\u0435\u043b\u044b\u0445 \u0447\u0438\u0441\u0435\u043b, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0432 <code>BitmapDescriptor<\/code> \u2014 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0431\u0438\u0442\u043c\u044d\u043f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e Google Maps \u043f\u043e\u0442\u043e\u043c \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u043a\u0430\u0440\u0442\u0435.<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 Flutter \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0438\u043a\u0441\u0435\u043b\u0438. \u041d\u043e, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u0430 \u043e\u0434\u0438\u043d \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0438\u043a\u0441\u0435\u043b\u044c \u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445. \u0427\u0442\u043e\u0431\u044b \u0438\u043a\u043e\u043d\u043a\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>scale<\/code>.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 <strong>main.dart:<\/strong><\/p>\n<pre><code class=\"dart\">class _CustomMapState extends State&lt;CustomMap> {   GoogleMapController? _controller;   final Set&lt;Marker> _markers = {};     final CustomMarkerDrawer _markerDrawer = CustomMarkerDrawer();   double _scale = 1;    ...   @override   initState() {     super.initState();     Future.delayed(Duration.zero, () {       _likedPlaceIds.addAll([_places[0].id, _places[3].id]);       _scale = MediaQuery.of(context).devicePixelRatio;       _mapPlacesToMarkers();     });   }   ... }<\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043e\u0442\u0434\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0430\u0441\u0441 <code>MediaQueryData<\/code> \u2014 \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0443 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432 Material-\u0432\u0438\u0434\u0436\u0435\u0442\u043e\u0432, \u0435\u0433\u043e \u043d\u0435\u0442 \u0432 \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c \u0432\u0438\u0434\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. <code>MediaQueryData.of(context)<\/code> \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0439 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>initState<\/code>, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043e\u0431\u0435\u0440\u043d\u0443\u043b \u0435\u0433\u043e \u0432 <code>Future.delayed(Duration.zero, () {...}<\/code> \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043b\u0435\u0436\u0430\u0449\u0435\u0433\u043e \u0432 \u043d\u0435\u043c \u043a\u043e\u0434\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0442\u0438\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c <code>initState<\/code> \u0443\u0436\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0437\u0430\u0432\u0435\u0440\u0448\u0451\u043d.<\/p>\n<p>\u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u0432\u0438\u0434 \u043a\u0430\u0440\u0442\u044b:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/db7\/dd7\/2eb\/db7dd72eb089a1dba196fd384baf6c21.png\" width=\"1080\" height=\"2220\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/db7\/dd7\/2eb\/db7dd72eb089a1dba196fd384baf6c21.png\"\/><figcaption><\/figcaption><\/figure>\n<p><a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/custom-icon-drawer\" rel=\"noopener noreferrer nofollow\">\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f<\/a><\/p>\n<p>\u0418\u0442\u0430\u043a, \u043c\u044b \u0443\u0432\u0438\u0434\u0435\u043b\u0438, \u043a\u0430\u043a \u0432\u043e Flutter \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c Google Maps, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0438\u0441\u044c \u0432\u043e\u043f\u0440\u043e\u0441\u044b \u2014 \u0441 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435\u043c \u043e\u0442\u0432\u0435\u0447\u0443.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/680092\/\"> https:\/\/habr.com\/ru\/post\/680092\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042f \u2014 \u0422\u0438\u043c, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0432 \u0413\u0443\u0434\u0438\u0442\u0432\u043e\u0440\u043a\u0441. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u043c\u044b \u0434\u0435\u043b\u0430\u043b\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0433\u0438\u0434 \u043f\u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430\u043c. \u041d\u0430\u043c \u0431\u044b\u043b\u043e \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u043a\u0430\u0440\u0442\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u043b\u0430\u0441\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430\u0445, \u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u0431\u044b \u043e\u0442\u043c\u0435\u0447\u0430\u0442\u044c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0432\u0448\u0438\u0435\u0441\u044f. \u042f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043e Flutter \u0441 \u043a\u0430\u0440\u0442\u0430\u043c\u0438, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u043c\u0430\u0440\u043a\u0435\u0440\u0430\u043c\u0438. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430 \u2014 \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043f\u043e\u043b\u043d\u044b\u043c \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0430.<\/p>\n<h2>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b  <\/h2>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u0430\u0440\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0441\u043d\u043e\u0432\u044b \u044f \u0432\u044b\u0431\u0440\u0430\u043b Google Maps. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u0438\u043c \u0432\u043e Flutter \u0435\u0441\u0442\u044c \u043f\u0430\u043a\u0435\u0442 <a href=\"https:\/\/pub.dev\/packages\/google_maps_flutter\" rel=\"noopener noreferrer nofollow\">google_maps_flutter<\/a>. \u041f\u0430\u043a\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0432 \u0444\u0430\u0439\u043b <strong>pubspec.yaml<\/strong>:<\/p>\n<pre><code class=\"yaml\">dependencies:   ...   google_maps_flutter: ^2.1.8   ...<\/code><\/pre>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043a\u0430\u0440\u0442\u0430\u043c, \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f API-\u043a\u043b\u044e\u0447: \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0435\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c, \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 <a href=\"https:\/\/developers.google.com\/maps\/documentation\/android-sdk\/get-api-key\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438<\/a> Maps SDK. \u0414\u043b\u044f Android \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043a\u043b\u044e\u0447 \u0432 \u0444\u0430\u0439\u043b <strong>android\/app\/src\/main\/AndroidManifest.xml<\/strong>:<\/p>\n<pre><code class=\"xml\">&lt;manifest ...    &lt;application ...         &lt;meta-data android:name=\"com.google.android.geo.API_KEY\"                    android:value=\"API-\u041a\u041b\u042e\u0427\"\/><\/code><\/pre>\n<p> \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0438\u0434\u0436\u0435\u0442 \u0441 \u043a\u0430\u0440\u0442\u043e\u0439 \u0432 \u0444\u0430\u0439\u043b <strong>main.dart<\/strong>:<\/p>\n<pre><code class=\"dart\">import 'package:flutter\/material.dart'; import 'package:flutter\/services.dart'; import 'package:google_maps_flutter\/google_maps_flutter.dart';  void main() => runApp(const MyApp());  class MyApp extends StatelessWidget {   const MyApp({Key? key}) : super(key: key);    @override   Widget build(BuildContext context) {     return const MaterialApp(       home: Scaffold(         body: CustomMap(),       ),     );   } }  class CustomMap extends StatefulWidget {   const CustomMap({Key? key}) : super(key: key);    @override   _CustomMapState createState() => _CustomMapState(); }  class _CustomMapState extends State&lt;CustomMap> {   GoogleMapController? _controller;   static const LatLng _center = LatLng(48.864716, 2.349014);    void _onMapCreated(GoogleMapController controller) {     setState(() {       _controller = controller;     });      rootBundle.loadString('assets\/map_style.json').then((mapStyle) {       _controller?.setMapStyle(mapStyle);     });   }    @override   Widget build(BuildContext context) {     return GoogleMap(       onMapCreated: _onMapCreated,       initialCameraPosition: const CameraPosition(         target: _center,         zoom: 12,       ),     );   } }<\/code><\/pre>\n<p>\u0421\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430:<\/p>\n<ul>\n<li>\n<p>\u043c\u0435\u0442\u043e\u0434 <code>_onMapCreated<\/code>: \u043e\u043d \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043a\u0430\u0440\u0442\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>GoogleMapController<\/code>,<\/p>\n<\/li>\n<li>\n<p>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>initialCameraPosition<\/code>: \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043f\u0435\u0440\u0432\u0438\u0447\u043d\u043e\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u0430\u0440\u0442\u044b,<\/p>\n<\/li>\n<li>\n<p><code>GoogleMapController<\/code>: \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u0430\u0440\u0442\u043e\u0439 \u2014 \u043f\u043e\u0437\u0438\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c, \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439, \u0437\u0443\u043c\u043e\u043c.<\/p>\n<\/li>\n<\/ul>\n<p>\u0427\u0442\u043e\u0431\u044b \u043a\u0430\u0440\u0442\u0430 \u0431\u044b\u043b\u0430 \u043a\u0440\u0430\u0441\u0438\u0432\u0435\u0435, \u044f \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u043b \u0441\u0442\u0438\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>assets\/map_style.json<\/strong>. \u0421\u0442\u0438\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u0430\u0440\u0442\u0443 \u0443\u0434\u043e\u0431\u043d\u043e \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c <a href=\"http:\/\/mapstyle.withgoogle.com\" rel=\"noopener noreferrer nofollow\">mapstyle.withgoogle.com<\/a>. \u0422\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0440\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:  <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/init-gm\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/init-gm<\/a><\/p>\n<h3>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b  <\/h3>\n<p>\u041d\u0430 \u043a\u0430\u0440\u0442\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0443\u0436\u043d\u044b \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b: \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d\u0438, \u043a\u0430\u043a \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u043e\u0432 \u2014 \u0432 \u0444\u0430\u0439\u043b\u0435 <strong>datasource.dart<\/strong><\/p>\n<p>\u041c\u0435\u0442\u043e\u0434 <code>_upsertMarker<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043c\u0430\u0440\u043a\u0435\u0440\u044b:<\/p>\n<pre><code class=\"dart\">void _upsertMarker(Place place) {     setState(() {       _markers.add(Marker(         markerId: MarkerId(place.id),         position: place.location,         infoWindow: InfoWindow(           title: place.name,           snippet:               [...place.occasions, ...place.vibes, ...place.budget].join(\", \"),         ),         icon: BitmapDescriptor.defaultMarker,       ));     });   }<\/code><\/pre>\n<p>\u041a\u043b\u0430\u0441\u0441 <code>infoWindow<\/code> \u043f\u043e \u0442\u0430\u043f\u0443 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u0438\u043d \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0435, \u0430 \u043d\u0430 \u043a\u0430\u0440\u0442\u0443 \u043c\u0430\u0440\u043a\u0435\u0440\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 <code>markers<\/code> \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <code>GoogleMap<\/code>:<\/p>\n<pre><code class=\"dart\">void _mapPlacesToMarkers() {   for (final place in _places) {     _upsertMarker(place);   } } ... @override initState() {   super.initState();   _mapPlacesToMarkers(); }  @override Widget build(BuildContext context) {   return GoogleMap(     onMapCreated: _onMapCreated,     initialCameraPosition: const CameraPosition(       target: _center,       zoom: 12,     ),     markers: _markers,   ); }<\/code><\/pre>\n<p>\u0412\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u044d\u0442\u043e \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/default-markers\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/default-markers<\/a><\/p>\n<h3>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e \u0442\u0430\u043f\u0443  <\/h3>\n<p>\u041d\u043e \u043f\u0438\u043d\u0430 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0430\u044f \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0441 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0435\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0442\u0430 \u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0435\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 \u0432 <code>_CustomMapState<\/code>. \u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0442\u0430\u043f\u0443 \u043d\u0430 \u043c\u0430\u0440\u043a\u0435\u0440 (\u043c\u0435\u0442\u043e\u0434 <code>_selectPlace<\/code>), \u0430 \u0438\u0441\u0447\u0435\u0437\u0430\u0442\u044c \u043f\u043e \u0442\u0430\u043f\u0443 \u0442\u0430\u043c, \u0433\u0434\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u0430 \u043d\u0435\u0442 (\u043c\u0435\u0442\u043e\u0434 <code>_unselectPlace<\/code>). \u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u0438\u0434\u0436\u0435\u0442\u0430 <code>Positioned<\/code>:<\/p>\n<pre><code class=\"dart\">class _CustomMapState extends State&lt;CustomMap> {   ...   final List&lt;Place> _places = places;   Place? _selectedPlace;      void _unselectPlace() {     setState(() {       _selectedPlace = null;     });   }      void _selectPlace(Place place) {     setState(() {       _selectedPlace = place;     });   }    void _upsertMarker(Place place) {     setState(() {       _markers.add(Marker(         ...         onTap: () => _selectPlace(place),         ...       ));     });   }   ...     @override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         GoogleMap(           ...           ),           markers: _markers,           onTap: (_) => _unselectPlace(),         ),         if (_selectedPlace != null)           Positioned(             bottom: 76,             child: PhysicalModel(               color: Colors.black,               shadowColor: Colors.black.withOpacity(0.6),               borderRadius: BorderRadius.circular(12),               elevation: 12,               child: Container(                 decoration: const BoxDecoration(                   color: Colors.white,                   borderRadius: BorderRadius.all(Radius.circular(12)),                 ),                 child: MapPlaceCard(                   place: _selectedPlace!,                 ),               ),             ),           ),       ],     );   }<\/code><\/pre>\n<p> \u0422\u0435\u043f\u0435\u0440\u044c \u043a\u0430\u0440\u0442\u0430 \u2014 \u0441 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0430\u043c\u0438:  <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/cards-on-tap\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/cards-on-tap<\/a>  <\/p>\n<h3>\u041c\u0435\u043d\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u044b  <\/h3>\n<p>\u0411\u044b\u043b\u043e \u0431\u044b \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u043e\u0442\u043c\u0435\u0447\u0430\u0442\u044c \u043f\u043e\u043d\u0440\u0430\u0432\u0438\u0432\u0448\u0438\u0435\u0441\u044f \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u044b, \u0438 \u043c\u0430\u0440\u043a\u0435\u0440 \u0431\u044b \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043c\u0435\u043d\u044f\u043b\u0441\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0438\u043a\u043e\u043d\u043a\u0438:  <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u041c\u0430\u0440\u043a\u0435\u0440\u044b \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>_upsertMarker<\/code>:<\/p>\n<pre><code class=\"dart\">Future&lt;void> _upsertMarker(Place place) async {     final selectedPrefix = place.id == _selectedPlace?.id ? \"selected_\" : \"\";     final favoritePostfix =         _likedPlaceIds.contains(place.id) ? \"_favorite\" : \"\";      final icon = await BitmapDescriptor.fromAssetImage(       const ImageConfiguration(),       \"assets\/icons\/${selectedPrefix}map_place$favoritePostfix.png\",     );      setState(() {       _markers.add(Marker(         markerId: MarkerId(place.id),         position: place.location,         onTap: () => _selectPlace(place),         icon: icon,       ));     });   }<\/code><\/pre>\n<p>\u0421\u0435\u0440\u0434\u0435\u0447\u043a\u043e-\u043b\u0430\u0439\u043a \u0441\u0442\u0430\u0432\u0438\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>_likeTapHandler<\/code>:<\/p>\n<pre><code class=\"dart\">void _likeTapHandler() async {     if (_selectedPlace == null) return;     setState(() {       if (_likedPlaceIds.contains(_selectedPlace!.id)) {         _likedPlaceIds.removeAt(_likedPlaceIds.indexOf(_selectedPlace!.id));       } else {         _likedPlaceIds.add(_selectedPlace!.id);       }     });      _upsertMarker(_selectedPlace!);   }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0436\u0435\u0442\u0435 <code>MapPlaceCard<\/code>:<\/p>\n<pre><code class=\"dart\">@override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         ...         if (_selectedPlace != null)           Positioned(             ...             child: PhysicalModel(               ...               child: Container(                 ...                 child: MapPlaceCard(                   place: _selectedPlace!,                   isLiked: _likedPlaceIds.contains(_selectedPlace!.id),                   likeTapHandler: _likeTapHandler,                 ),               ),             ),           ),       ],     );   }<\/code><\/pre>\n<p>\u041a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0434\u0440\u0443\u0433\u043e\u0435 \u043c\u0435\u0441\u0442\u043e, \u0438\u043a\u043e\u043d\u043a\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e. \u042d\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u043c\u0435\u0442\u043e\u0434 <code>_unselectPlace<\/code> \u2014 \u043e\u043d \u0441\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u044b\u0431\u043e\u0440 \u0441 \u043c\u0435\u0441\u0442\u0430 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u0438\u043a\u043e\u043d\u043a\u0443:<\/p>\n<pre><code class=\"dart\">class _CustomMapState extends State&lt;CustomMap> {   ...   Future&lt;void> _unselectPlace() async {     if (_selectedPlace == null) return;      final place = _selectedPlace;     setState(() {       _selectedPlace = null;     });      await _upsertMarker(place!);   }    Future&lt;void> _selectPlace(Place place) async {     await _unselectPlace();      setState(() {       _selectedPlace = place;     });      await _upsertMarker(place);   }   ...   @override   Widget build(BuildContext context) {     return Stack(       ...       children: &lt;Widget>[         GoogleMap(           ...           ),           markers: _markers,           onTap: (_) => _unselectPlace(),         ),         if (_selectedPlace != null)           Positioned(             bottom: 76,             child: PhysicalModel(               color: Colors.black,               shadowColor: Colors.black.withOpacity(0.6),               borderRadius: BorderRadius.circular(12),               elevation: 12,               child: Container(                 decoration: const BoxDecoration(                   color: Colors.white,                   borderRadius: BorderRadius.all(Radius.circular(12)),                 ),                 child: MapPlaceCard(                   place: _selectedPlace!,                   isLiked: _likedPlaceIds.contains(_selectedPlace!.id),                   likeTapHandler: _likeTapHandler,                 ),               ),             ),           ),       ],     );   } }<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0430 \u043a\u0430\u0440\u0442\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<figure class=\"full-width\"><figcaption>\u0421\u043b\u0435\u0432\u0430 \u2014 \u043d\u0435\u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d, \u0441\u043f\u0440\u0430\u0432\u0430 \u2014 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439<\/figcaption><\/figure>\n<p>\u0412\u0435\u0442\u043a\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f: <a href=\"https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/different-icons\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/gooditcollective\/flutter-google-maps-exmaple\/tree\/different-icons<\/a><\/p>\n<h3>\u041d\u0435\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043c\u0430\u0440\u043a\u0435\u0440\u044b<\/h3>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u2014 \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0442\u043e\u0440\u0430\u043d\u0430 \u0431\u044b\u043b\u043e \u0432\u0438\u0434\u043d\u043e \u0432\u0441\u0435\u0433\u0434\u0430, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e \u0442\u0430\u043f\u0443. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e \u0443\u0442\u0438\u043b\u0438\u0442\u0443 \u0434\u043b\u044f \u0440\u0438\u0441\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u0430 <strong>utils\/custom_marker_drawer.dart<\/strong><\/p>\n<pre><code class=\"dart\">... class CustomMarkerDrawer {   ...   Future&lt;CustomMarker> createCustomMarkerBitmap({     ...   }) async {     ...     PictureRecorder recorder = PictureRecorder();     Canvas canvas = Canvas(       recorder,       Rect.fromLTWH(         0,         0,<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-336397","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/336397","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=336397"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/336397\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=336397"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=336397"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=336397"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}