diff --git a/packages/google_maps_flutter/google_maps_flutter/AUTHORS b/packages/google_maps_flutter/google_maps_flutter/AUTHORS index 9f1b53ee2667..4fc3ace39f0f 100644 --- a/packages/google_maps_flutter/google_maps_flutter/AUTHORS +++ b/packages/google_maps_flutter/google_maps_flutter/AUTHORS @@ -65,3 +65,4 @@ Anton Borries Alex Li Rahul Raj <64.rahulraj@gmail.com> Taha Tesser +Joonas Kerttula diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md index fd0b4223dfec..c92f63deb0eb 100644 --- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md @@ -1,6 +1,7 @@ -## NEXT +## 2.7.0 -* Updates minimum supported SDK version to Flutter 3.16/Dart 3.2. +* Adds support for BitmapDescriptor classes `AssetMapBitmap` and `BytesMapBitmap`. +* Updates minimum supported SDK version to Flutter 3.22/Dart 3.4. ## 2.6.1 diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/maps_controller.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/maps_controller.dart index 3d99369e33be..2ab5ffccccbc 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/maps_controller.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/maps_controller.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. import 'dart:async'; +import 'dart:convert'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -10,6 +11,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:integration_test/integration_test.dart'; +import 'resources/icon_image_base64.dart'; import 'shared.dart'; /// Integration Tests that only need a standard [GoogleMapController]. @@ -401,6 +403,112 @@ void runTests() { expect(iwVisibleStatus, false); }); + testWidgets('markerWithAssetMapBitmap', (WidgetTester tester) async { + final Set markers = { + Marker( + markerId: const MarkerId('1'), + icon: AssetMapBitmap( + 'assets/red_square.png', + imagePixelRatio: 1.0, + )), + }; + await pumpMap( + tester, + GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + ), + ); + }); + + testWidgets('markerWithAssetMapBitmapCreate', (WidgetTester tester) async { + final ImageConfiguration imageConfiguration = ImageConfiguration( + devicePixelRatio: tester.view.devicePixelRatio, + ); + final Set markers = { + Marker( + markerId: const MarkerId('1'), + icon: await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + )), + }; + await pumpMap( + tester, + GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + ), + ); + }); + + testWidgets('markerWithBytesMapBitmap', (WidgetTester tester) async { + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + final Set markers = { + Marker( + markerId: const MarkerId('1'), + icon: BytesMapBitmap( + bytes, + imagePixelRatio: tester.view.devicePixelRatio, + ), + ), + }; + await pumpMap( + tester, + GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + ), + ); + }); + + testWidgets('markerWithLegacyAsset', (WidgetTester tester) async { + tester.view.devicePixelRatio = 2.0; + final ImageConfiguration imageConfiguration = ImageConfiguration( + devicePixelRatio: tester.view.devicePixelRatio, + size: const Size(100, 100), + ); + final Set markers = { + Marker( + markerId: const MarkerId('1'), + icon: await BitmapDescriptor.fromAssetImage( + imageConfiguration, + 'assets/red_square.png', + )), + }; + await pumpMap( + tester, + GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + ), + ); + + await tester.pumpAndSettle(); + }); + + testWidgets('markerWithLegacyBytes', (WidgetTester tester) async { + tester.view.devicePixelRatio = 2.0; + final Uint8List bytes = const Base64Decoder().convert(iconImageBase64); + final Set markers = { + Marker( + markerId: const MarkerId('1'), + icon: BitmapDescriptor.fromBytes( + bytes, + size: const Size(100, 100), + )), + }; + await pumpMap( + tester, + GoogleMap( + initialCameraPosition: const CameraPosition(target: LatLng(10.0, 15.0)), + markers: markers, + ), + ); + + await tester.pumpAndSettle(); + }); + testWidgets('testTakeSnapshot', (WidgetTester tester) async { final Completer controllerCompleter = Completer(); diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image.png b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image.png new file mode 100644 index 000000000000..920b93f74d78 Binary files /dev/null and b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image.png differ diff --git a/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image_base64.dart b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image_base64.dart new file mode 100644 index 000000000000..1bfc791ca385 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/integration_test/src/resources/icon_image_base64.dart @@ -0,0 +1,49 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/// This constant holds the base64-encoded data of a 16x16 PNG image of the +/// Flutter logo. +/// +/// See `icon_image.png` source in the same directory. +/// +/// To create or update this image, follow these steps: +/// 1. Create or update a 16x16 PNG image. +/// 2. Convert the image to a base64 string using a script below. +/// 3. Replace the existing base64 string below with the new one. +/// +/// Example of converting an image to base64 in Dart: +/// ```dart +/// import 'dart:convert'; +/// import 'dart:io'; +/// +/// void main() async { +/// final bytes = await File('icon_image.png').readAsBytes(); +/// final base64String = base64Encode(bytes); +/// print(base64String); +/// } +/// ``` +const String iconImageBase64 = + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIRlWElmTU' + '0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA' + 'AIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQ' + 'AAABCgAwAEAAAAAQAAABAAAAAAx28c8QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1M' + 'OmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIH' + 'g6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8v' + 'd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcm' + 'lwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFk' + 'b2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk' + '9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6' + 'eG1wbWV0YT4KTMInWQAAAplJREFUOBF1k01ME1EQx2fe7tIPoGgTE6AJgQQSPaiH9oAtkFbsgX' + 'jygFcT0XjSkxcTDxtPJh6MR28ePMHBBA8cNLSIony0oBhEMVETP058tE132+7uG3cW24DAXN57' + '2fn9/zPz3iIcEdEl0nIxtNLr1IlVeoMadkubKmoL+u2SzAV8IjV5Ekt4GN+A8+VOUPwLarOI2G' + 'Vpqq0i4JQorwQxPtWHVZ1IKP8LNGDXGaSyqARFxDGo7MJBy4XVf3AyQ+qTHnTEXoF9cFUy3OkY' + '0oWxmWFtD5xNoc1sQ6AOn1+hCNTkkhKow8KFZV77tVs2O9dhFvBm0IA/U0RhZ7/ocEx23oUDlh' + 'h8HkNjZIN8Lb3gOU8gOp7AKJHCB2/aNZkTftHumNzzbtl2CBPZHqxw8mHhVZBeoz6w5DvhE2FZ' + 'lQYPjKdd2/qRyKZ6KsPv7TEk7EYEk0A0EUmJduHRy1i4oLKqgmC59ZggAdwrC9pFuWy1iUT2rA' + 'uv0h2UdNtNqxCBBkgqorjOMOgksN7CxQ90vEb00U3c3LIwyo9o8FXxQVNr8Coqyk+S5EPBXnjt' + 'xRmc4TegI7qWbvBkeeUbGMnTCd4nZnYeDOWIEtlC6cKK/JJepY3hZSvN33jovO6L0XFqPKqBTO' + 'FuapUoPr1lxDM7cmC2TAOz25cYSGa++feBew/cjpc0V+mNT29/HZp3KDFTNLvuTRPEHy5065lj' + 'Xn4y41XM+wP/AlcycRmdc3MUhvLm/J/ceu/3qUVT62oP2EZpjSylHybHSpDUVcjq9gEBVo0+Xt' + 'JyN2IWRO+3QUforRoKnZLVsglaMECW+YmMSj9M3SrC6Lg71CMiqWfUrJ6ywzefhnZ+G69BaKdB' + 'WhXQAn6wzDUpfUPw7MrmX/WhbfmKblw+AAAAAElFTkSuQmCC'; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/custom_marker_icon.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/custom_marker_icon.dart new file mode 100644 index 000000000000..8940762f02e4 --- /dev/null +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/custom_marker_icon.dart @@ -0,0 +1,56 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:typed_data'; +import 'dart:ui' as ui; + +import 'package:flutter/material.dart'; + +/// Returns a generated png image in [ByteData] format with the requested size. +Future createCustomMarkerIconImage({required Size size}) async { + final ui.PictureRecorder recorder = ui.PictureRecorder(); + final Canvas canvas = Canvas(recorder); + final _MarkerPainter painter = _MarkerPainter(); + + painter.paint(canvas, size); + + final ui.Image image = await recorder + .endRecording() + .toImage(size.width.floor(), size.height.floor()); + + final ByteData? bytes = + await image.toByteData(format: ui.ImageByteFormat.png); + return bytes!; +} + +class _MarkerPainter extends CustomPainter { + @override + void paint(Canvas canvas, Size size) { + final Rect rect = Offset.zero & size; + const RadialGradient gradient = RadialGradient( + colors: [Colors.yellow, Colors.red], + stops: [0.4, 1.0], + ); + + // Draw radial gradient + canvas.drawRect( + rect, + Paint()..shader = gradient.createShader(rect), + ); + + // Draw diagonal black line + canvas.drawLine( + Offset.zero, + Offset(size.width, size.height), + Paint() + ..color = Colors.black + ..strokeWidth = 1, + ); + } + + @override + bool shouldRepaint(_MarkerPainter oldDelegate) => false; + @override + bool shouldRebuildSemantics(_MarkerPainter oldDelegate) => false; +} diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart index 847e5ae3678b..d2010b65b13b 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/marker_icons.dart @@ -5,9 +5,13 @@ // ignore_for_file: public_member_api_docs // ignore_for_file: unawaited_futures +import 'dart:async'; + +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'custom_marker_icon.dart'; import 'page.dart'; class MarkerIconsPage extends GoogleMapExampleAppPage { @@ -29,66 +33,303 @@ class MarkerIconsBody extends StatefulWidget { const LatLng _kMapCenter = LatLng(52.4478, -3.5402); +enum _MarkerSizeOption { + original, + width30, + height40, + size30x60, + size120x60, +} + class MarkerIconsBodyState extends State { + final Size _markerAssetImageSize = const Size(48, 48); + _MarkerSizeOption _currentSizeOption = _MarkerSizeOption.original; + Set _markers = {}; + bool _scalingEnabled = true; + bool _mipMapsEnabled = true; GoogleMapController? controller; - BitmapDescriptor? _markerIcon; + AssetMapBitmap? _markerIconAsset; + BytesMapBitmap? _markerIconBytes; + final int _markersAmountPerType = 15; + bool get _customSizeEnabled => + _currentSizeOption != _MarkerSizeOption.original; @override Widget build(BuildContext context) { - _createMarkerImageFromAsset(context); + _createCustomMarkerIconImages(context); + final Size referenceSize = _getMarkerReferenceSize(); return Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Center( - child: SizedBox( - width: 350.0, - height: 300.0, - child: GoogleMap( - initialCameraPosition: const CameraPosition( - target: _kMapCenter, - zoom: 7.0, + Column(children: [ + Center( + child: SizedBox( + width: 350.0, + height: 300.0, + child: GoogleMap( + initialCameraPosition: const CameraPosition( + target: _kMapCenter, + zoom: 7.0, + ), + markers: _markers, + onMapCreated: _onMapCreated, + ), + ), + ), + TextButton( + onPressed: () => _toggleScaling(context), + child: Text(_scalingEnabled + ? 'Disable auto scaling' + : 'Enable auto scaling'), + ), + if (_scalingEnabled) ...[ + Container( + width: referenceSize.width, + height: referenceSize.height, + decoration: BoxDecoration( + border: Border.all(), ), - markers: {_createMarker()}, - onMapCreated: _onMapCreated, ), + Text( + 'Reference box with size of ${referenceSize.width} x ${referenceSize.height} in logical pixels.'), + const SizedBox(height: 10), + Image.asset( + 'assets/red_square.png', + scale: _mipMapsEnabled ? null : 1.0, + ), + const Text('Asset image rendered with flutter'), + const SizedBox(height: 10), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Marker size:'), + const SizedBox(width: 10), + DropdownButton<_MarkerSizeOption>( + value: _currentSizeOption, + onChanged: (_MarkerSizeOption? newValue) { + if (newValue != null) { + setState(() { + _currentSizeOption = newValue; + _updateMarkerImages(context); + }); + } + }, + items: + _MarkerSizeOption.values.map((_MarkerSizeOption option) { + return DropdownMenuItem<_MarkerSizeOption>( + value: option, + child: Text(_getMarkerSizeOptionName(option)), + ); + }).toList(), + ) + ], + ), + ], + TextButton( + onPressed: () => _toggleMipMaps(context), + child: Text(_mipMapsEnabled ? 'Disable mipmaps' : 'Enable mipmaps'), ), - ) + ]) ], ); } - Marker _createMarker() { - if (_markerIcon != null) { - return Marker( - markerId: const MarkerId('marker_1'), - position: _kMapCenter, - icon: _markerIcon!, - ); + String _getMarkerSizeOptionName(_MarkerSizeOption option) { + switch (option) { + case _MarkerSizeOption.original: + return 'Original'; + case _MarkerSizeOption.width30: + return 'Width 30'; + case _MarkerSizeOption.height40: + return 'Height 40'; + case _MarkerSizeOption.size30x60: + return '30x60'; + case _MarkerSizeOption.size120x60: + return '120x60'; + } + } + + (double? width, double? height) _getCurrentMarkerSize() { + if (_scalingEnabled) { + switch (_currentSizeOption) { + case _MarkerSizeOption.width30: + return (30, null); + case _MarkerSizeOption.height40: + return (null, 40); + case _MarkerSizeOption.size30x60: + return (30, 60); + case _MarkerSizeOption.size120x60: + return (120, 60); + case _MarkerSizeOption.original: + return (_markerAssetImageSize.width, _markerAssetImageSize.height); + } } else { - return const Marker( - markerId: MarkerId('marker_1'), - position: _kMapCenter, - ); + return (_markerAssetImageSize.width, _markerAssetImageSize.height); } } - Future _createMarkerImageFromAsset(BuildContext context) async { - if (_markerIcon == null) { - final ImageConfiguration imageConfiguration = - createLocalImageConfiguration(context, size: const Size.square(48)); - BitmapDescriptor.fromAssetImage( - imageConfiguration, 'assets/red_square.png') - .then(_updateBitmap); + // Helper method to calculate reference size for custom marker size. + Size _getMarkerReferenceSize() { + final (double? width, double? height) = _getCurrentMarkerSize(); + + // Calculates reference size using _markerAssetImageSize aspect ration: + + if (width != null && height != null) { + return Size(width, height); + } else if (width != null) { + return Size(width, + width * _markerAssetImageSize.height / _markerAssetImageSize.width); + } else if (height != null) { + return Size( + height * _markerAssetImageSize.width / _markerAssetImageSize.height, + height); + } else { + return _markerAssetImageSize; } } - void _updateBitmap(BitmapDescriptor bitmap) { + void _toggleMipMaps(BuildContext context) { + _mipMapsEnabled = !_mipMapsEnabled; + _updateMarkerImages(context); + } + + void _toggleScaling(BuildContext context) { + _scalingEnabled = !_scalingEnabled; + _updateMarkerImages(context); + } + + void _updateMarkerImages(BuildContext context) { + _updateMarkerAssetImage(context); + _updateMarkerBytesImage(context); + _updateMarkers(); + } + + Marker _createAssetMarker(int index) { + final LatLng position = + LatLng(_kMapCenter.latitude - (index * 0.5), _kMapCenter.longitude - 1); + + return Marker( + markerId: MarkerId('marker_asset_$index'), + position: position, + icon: _markerIconAsset!, + ); + } + + Marker _createBytesMarker(int index) { + final LatLng position = + LatLng(_kMapCenter.latitude - (index * 0.5), _kMapCenter.longitude + 1); + + return Marker( + markerId: MarkerId('marker_bytes_$index'), + position: position, + icon: _markerIconBytes!, + ); + } + + void _updateMarkers() { + final Set markers = {}; + for (int i = 0; i < _markersAmountPerType; i++) { + if (_markerIconAsset != null) { + markers.add(_createAssetMarker(i)); + } + if (_markerIconBytes != null) { + markers.add(_createBytesMarker(i)); + } + } setState(() { - _markerIcon = bitmap; + _markers = markers; }); } + Future _updateMarkerAssetImage(BuildContext context) async { + // Width and height are used only for custom size. + final (double? width, double? height) = + _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + AssetMapBitmap assetMapBitmap; + if (_mipMapsEnabled) { + final ImageConfiguration imageConfiguration = + createLocalImageConfiguration( + context, + ); + + assetMapBitmap = await AssetMapBitmap.create( + imageConfiguration, + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: + _scalingEnabled ? MapBitmapScaling.auto : MapBitmapScaling.none, + ); + } else { + // Uses hardcoded asset path + // This bypasses the asset resolving logic and allows to load the asset + // with precise path. + assetMapBitmap = AssetMapBitmap( + 'assets/red_square.png', + width: width, + height: height, + bitmapScaling: + _scalingEnabled ? MapBitmapScaling.auto : MapBitmapScaling.none, + ); + } + + _updateAssetBitmap(assetMapBitmap); + } + + Future _updateMarkerBytesImage(BuildContext context) async { + final double? devicePixelRatio = + MediaQuery.maybeDevicePixelRatioOf(context); + + final Size bitmapLogicalSize = _getMarkerReferenceSize(); + final double? imagePixelRatio = _scalingEnabled ? devicePixelRatio : null; + + // Create canvasSize with physical marker size + final Size canvasSize = Size( + bitmapLogicalSize.width * (imagePixelRatio ?? 1.0), + bitmapLogicalSize.height * (imagePixelRatio ?? 1.0)); + + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + + // Width and height are used only for custom size. + final (double? width, double? height) = + _scalingEnabled && _customSizeEnabled + ? _getCurrentMarkerSize() + : (null, null); + + final BytesMapBitmap bitmap = BytesMapBitmap(bytes.buffer.asUint8List(), + imagePixelRatio: imagePixelRatio, + width: width, + height: height, + bitmapScaling: + _scalingEnabled ? MapBitmapScaling.auto : MapBitmapScaling.none); + + _updateBytesBitmap(bitmap); + } + + void _updateAssetBitmap(AssetMapBitmap bitmap) { + _markerIconAsset = bitmap; + _updateMarkers(); + } + + void _updateBytesBitmap(BytesMapBitmap bitmap) { + _markerIconBytes = bitmap; + _updateMarkers(); + } + + void _createCustomMarkerIconImages(BuildContext context) { + if (_markerIconAsset == null) { + _updateMarkerAssetImage(context); + } + + if (_markerIconBytes == null) { + _updateMarkerBytesImage(context); + } + } + void _onMapCreated(GoogleMapController controllerParam) { setState(() { controller = controllerParam; diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart index dc3a087058ce..1534f3b64ba1 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart +++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/place_marker.dart @@ -7,11 +7,11 @@ import 'dart:async'; import 'dart:math'; import 'dart:typed_data'; -import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'custom_marker_icon.dart'; import 'page.dart'; class PlaceMarkerPage extends GoogleMapExampleAppPage { @@ -266,26 +266,10 @@ class PlaceMarkerBodyState extends State { }); } - Future _getAssetIcon(BuildContext context) async { - final Completer bitmapIcon = - Completer(); - final ImageConfiguration config = createLocalImageConfiguration(context); - - const AssetImage('assets/red_square.png') - .resolve(config) - .addListener(ImageStreamListener((ImageInfo image, bool sync) async { - final ByteData? bytes = - await image.image.toByteData(format: ImageByteFormat.png); - if (bytes == null) { - bitmapIcon.completeError(Exception('Unable to encode icon')); - return; - } - final BitmapDescriptor bitmap = - BitmapDescriptor.fromBytes(bytes.buffer.asUint8List()); - bitmapIcon.complete(bitmap); - })); - - return bitmapIcon.future; + Future _getMarkerIcon(BuildContext context) async { + const Size canvasSize = Size(48, 48); + final ByteData bytes = await createCustomMarkerIconImage(size: canvasSize); + return BytesMapBitmap(bytes.buffer.asUint8List()); } @override @@ -382,7 +366,7 @@ class PlaceMarkerBodyState extends State { onPressed: selectedId == null ? null : () { - _getAssetIcon(context).then( + _getMarkerIcon(context).then( (BitmapDescriptor icon) { _setMarkerIcon(selectedId, icon); }, diff --git a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml index 7b0d2a3276f8..4911beb65792 100644 --- a/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/example/pubspec.yaml @@ -18,8 +18,8 @@ dependencies: # The example app is bundled with the plugin so we use a path dependency on # the parent directory to use the current plugin's version. path: ../ - google_maps_flutter_android: ^2.5.0 - google_maps_flutter_platform_interface: ^2.5.0 + google_maps_flutter_android: ^2.9.0 + google_maps_flutter_platform_interface: ^2.7.0 dev_dependencies: build_runner: ^2.1.10 diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart index 7dbcee8e92cb..7eb4af947318 100644 --- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart +++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart @@ -17,7 +17,9 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf show ArgumentCallback, ArgumentCallbacks, + AssetMapBitmap, BitmapDescriptor, + BytesMapBitmap, CameraPosition, CameraPositionCallback, CameraTargetBounds, @@ -29,6 +31,7 @@ export 'package:google_maps_flutter_platform_interface/google_maps_flutter_platf JointType, LatLng, LatLngBounds, + MapBitmapScaling, MapStyleException, MapType, Marker, diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml index 5061448ac3e5..3ab5430b0955 100644 --- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml @@ -2,11 +2,11 @@ name: google_maps_flutter description: A Flutter plugin for integrating Google Maps in iOS and Android applications. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.6.1 +version: 2.7.0 environment: - sdk: ^3.3.0 - flutter: ">=3.19.0" + sdk: ^3.4.0 + flutter: ">=3.22.0" flutter: plugin: @@ -21,10 +21,10 @@ flutter: dependencies: flutter: sdk: flutter - google_maps_flutter_android: ^2.7.0 - google_maps_flutter_ios: ^2.5.0 - google_maps_flutter_platform_interface: ^2.6.0 - google_maps_flutter_web: ^0.5.6 + google_maps_flutter_android: ^2.9.0 + google_maps_flutter_ios: ^2.7.0 + google_maps_flutter_platform_interface: ^2.7.0 + google_maps_flutter_web: ^0.5.8 dev_dependencies: flutter_test: