55// ignore_for_file: public_member_api_docs
66// ignore_for_file: unawaited_futures
77
8+ import 'dart:async' ;
9+ import 'dart:math' ;
10+ import 'dart:typed_data' ;
11+
812import 'package:flutter/material.dart' ;
913import 'package:google_maps_flutter/google_maps_flutter.dart' ;
1014
15+ import 'custom_marker_icon.dart' ;
1116import 'page.dart' ;
1217
1318class MarkerIconsPage extends GoogleMapExampleAppPage {
@@ -30,65 +35,235 @@ class MarkerIconsBody extends StatefulWidget {
3035const LatLng _kMapCenter = LatLng (52.4478 , - 3.5402 );
3136
3237class MarkerIconsBodyState extends State <MarkerIconsBody > {
38+ final double _markerAssetImageSize = 48 ;
39+ final Size _customSize = const Size (55 , 30 );
40+ Set <Marker > _markers = < Marker > {};
41+ double _markerScale = 1.0 ;
42+ bool _scalingEnabled = true ;
43+ bool _customSizeEnabled = false ;
44+ bool _mipMapsEnabled = true ;
3345 GoogleMapController ? controller;
34- BitmapDescriptor ? _markerIcon;
46+ BitmapDescriptor ? _markerIconAsset;
47+ BitmapDescriptor ? _markerIconBytes;
48+ final int _markersAmountPerType = 15 ;
3549
3650 @override
3751 Widget build (BuildContext context) {
38- _createMarkerImageFromAsset (context);
52+ _createCustomMarkerIconImages (context);
53+ final Size size = getCurrentMarkerSize ();
3954 return Column (
4055 mainAxisAlignment: MainAxisAlignment .spaceEvenly,
4156 crossAxisAlignment: CrossAxisAlignment .stretch,
4257 children: < Widget > [
43- Center (
44- child: SizedBox (
45- width: 350.0 ,
46- height: 300.0 ,
47- child: GoogleMap (
48- initialCameraPosition: const CameraPosition (
49- target: _kMapCenter,
50- zoom: 7.0 ,
58+ Column (children: < Widget > [
59+ Center (
60+ child: SizedBox (
61+ width: 350.0 ,
62+ height: 300.0 ,
63+ child: GoogleMap (
64+ initialCameraPosition: const CameraPosition (
65+ target: _kMapCenter,
66+ zoom: 7.0 ,
67+ ),
68+ markers: _markers,
69+ onMapCreated: _onMapCreated,
5170 ),
52- markers: < Marker > {_createMarker ()},
53- onMapCreated: _onMapCreated,
5471 ),
5572 ),
56- )
73+ TextButton (
74+ onPressed: () => _toggleScaling (context),
75+ child: Text (_scalingEnabled
76+ ? 'Disable auto scaling'
77+ : 'Enable auto scaling' ),
78+ ),
79+ if (_scalingEnabled) ...< Widget > [
80+ Container (
81+ width: size.width,
82+ height: size.height,
83+ color: Colors .red,
84+ ),
85+ Text (
86+ 'Reference box with size of ${size .width } x ${size .height } in logical pixels.' ),
87+ const SizedBox (height: 10 ),
88+ TextButton (
89+ onPressed: () => _toggleCustomSize (context),
90+ child: Text (_customSizeEnabled
91+ ? 'Disable custom size'
92+ : 'Enable custom size' ),
93+ ),
94+ if (_customSizeEnabled)
95+ Row (
96+ mainAxisAlignment: MainAxisAlignment .spaceEvenly,
97+ children: < Widget > [
98+ TextButton (
99+ onPressed: _markerScale <= 0.5
100+ ? null
101+ : () => _decreaseScale (context),
102+ child: const Text (
103+ '-' ,
104+ textScaleFactor: 2 ,
105+ ),
106+ ),
107+ Text ('scale ${_markerScale }x' ),
108+ TextButton (
109+ onPressed: _markerScale >= 2.5
110+ ? null
111+ : () => _increaseScale (context),
112+ child: const Text (
113+ '+' ,
114+ textScaleFactor: 2 ,
115+ ),
116+ ),
117+ ],
118+ ),
119+ ],
120+ TextButton (
121+ onPressed: () => _toggleMipMaps (context),
122+ child: Text (_mipMapsEnabled ? 'Disable mipmaps' : 'Enable mipmaps' ),
123+ ),
124+ ])
57125 ],
58126 );
59127 }
60128
61- Marker _createMarker () {
62- if (_markerIcon != null ) {
63- return Marker (
64- markerId: const MarkerId ('marker_1' ),
65- position: _kMapCenter,
66- icon: _markerIcon! ,
67- );
68- } else {
69- return const Marker (
70- markerId: MarkerId ('marker_1' ),
71- position: _kMapCenter,
72- );
73- }
129+ Size getCurrentMarkerSize () {
130+ return _scalingEnabled && _customSizeEnabled
131+ ? _customSize * _markerScale
132+ : Size (_markerAssetImageSize, _markerAssetImageSize);
74133 }
75134
76- Future <void > _createMarkerImageFromAsset (BuildContext context) async {
77- if (_markerIcon == null ) {
78- final ImageConfiguration imageConfiguration =
79- createLocalImageConfiguration (context, size: const Size .square (48 ));
80- BitmapDescriptor .fromAssetImage (
81- imageConfiguration, 'assets/red_square.png' )
82- .then (_updateBitmap);
83- }
135+ void _toggleMipMaps (BuildContext context) {
136+ _mipMapsEnabled = ! _mipMapsEnabled;
137+ _updateMarkerImages (context);
138+ }
139+
140+ void _toggleScaling (BuildContext context) {
141+ _scalingEnabled = ! _scalingEnabled;
142+ _updateMarkerImages (context);
143+ }
144+
145+ void _toggleCustomSize (BuildContext context) {
146+ _customSizeEnabled = ! _customSizeEnabled;
147+ _updateMarkerImages (context);
148+ }
149+
150+ void _decreaseScale (BuildContext context) {
151+ _markerScale = max (_markerScale - 0.5 , 0.0 );
152+ _updateMarkerImages (context);
153+ }
154+
155+ void _increaseScale (BuildContext context) {
156+ _markerScale = min (_markerScale + 0.5 , 2.5 );
157+ _updateMarkerImages (context);
158+ }
159+
160+ void _updateMarkerImages (BuildContext context) {
161+ _updateMarkerAssetImage (context);
162+ _updateMarkerBytesImage (context);
163+ _updateMarkers ();
164+ }
165+
166+ Marker _createAssetMarker (int index) {
167+ final LatLng position =
168+ LatLng (_kMapCenter.latitude - (index * 0.5 ), _kMapCenter.longitude - 1 );
169+
170+ return Marker (
171+ markerId: MarkerId ('marker_asset_$index ' ),
172+ position: position,
173+ icon: _markerIconAsset! ,
174+ );
175+ }
176+
177+ Marker _createBytesMarker (int index) {
178+ final LatLng position =
179+ LatLng (_kMapCenter.latitude - (index * 0.5 ), _kMapCenter.longitude + 1 );
180+
181+ return Marker (
182+ markerId: MarkerId ('marker_bytes_$index ' ),
183+ position: position,
184+ icon: _markerIconBytes! ,
185+ );
84186 }
85187
86- void _updateBitmap (BitmapDescriptor bitmap) {
188+ void _updateMarkers () {
189+ final Set <Marker > markers = < Marker > {};
190+ for (int i = 0 ; i < _markersAmountPerType; i++ ) {
191+ if (_markerIconAsset != null ) {
192+ markers.add (_createAssetMarker (i));
193+ }
194+ if (_markerIconBytes != null ) {
195+ markers.add (_createBytesMarker (i));
196+ }
197+ }
87198 setState (() {
88- _markerIcon = bitmap ;
199+ _markers = markers ;
89200 });
90201 }
91202
203+ Future <void > _updateMarkerAssetImage (BuildContext context) async {
204+ final Size ? size =
205+ _scalingEnabled && _customSizeEnabled ? getCurrentMarkerSize () : null ;
206+ final ImageConfiguration imageConfiguration = createLocalImageConfiguration (
207+ context,
208+ size: size,
209+ );
210+ BitmapDescriptor .createFromAsset (
211+ imageConfiguration, 'assets/red_square.png' ,
212+ mipmaps: _mipMapsEnabled,
213+ imagePixelRatio: _mipMapsEnabled ? null : 1.0 ,
214+ bitmapScaling:
215+ _scalingEnabled ? BitmapScaling .auto : BitmapScaling .noScaling)
216+ .then (_updateAssetBitmap);
217+ }
218+
219+ Future <void > _updateMarkerBytesImage (BuildContext context) async {
220+ final double devicePixelRatio =
221+ WidgetsBinding .instance.window.devicePixelRatio;
222+
223+ final Size markerSize = getCurrentMarkerSize ();
224+
225+ final double ? imagePixelRatio = _scalingEnabled ? devicePixelRatio : null ;
226+
227+ // Create canvasSize with physical marker size
228+ final Size canvasSize = Size (markerSize.width * (imagePixelRatio ?? 1.0 ),
229+ markerSize.height * (imagePixelRatio ?? 1.0 ));
230+
231+ final ByteData bytes = await createCustomMarkerIconImage (size: canvasSize);
232+
233+ // Size is used only for custom size
234+ final Size ? size =
235+ _scalingEnabled && _customSizeEnabled ? getCurrentMarkerSize () : null ;
236+
237+ final BitmapDescriptor bitmap = BitmapDescriptor .createFromBytes (
238+ bytes.buffer.asUint8List (),
239+ imagePixelRatio: _customSizeEnabled ? null : imagePixelRatio,
240+ size: size,
241+ bitmapScaling:
242+ _scalingEnabled ? BitmapScaling .auto : BitmapScaling .noScaling);
243+
244+ _updateBytesBitmap (bitmap);
245+ }
246+
247+ void _updateAssetBitmap (BitmapDescriptor bitmap) {
248+ _markerIconAsset = bitmap;
249+ _updateMarkers ();
250+ }
251+
252+ void _updateBytesBitmap (BitmapDescriptor bitmap) {
253+ _markerIconBytes = bitmap;
254+ _updateMarkers ();
255+ }
256+
257+ void _createCustomMarkerIconImages (BuildContext context) {
258+ if (_markerIconAsset == null ) {
259+ _updateMarkerAssetImage (context);
260+ }
261+
262+ if (_markerIconBytes == null ) {
263+ _updateMarkerBytesImage (context);
264+ }
265+ }
266+
92267 void _onMapCreated (GoogleMapController controllerParam) {
93268 setState (() {
94269 controller = controllerParam;
0 commit comments