import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Maps 2.0.x Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: MyHomePage(title: 'Maps 2.0.x Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
GoogleMapController? controller;
TileOverlay? _tileOverlay;
void _onMapCreated(GoogleMapController controller) {
this.controller = controller;
}
@override
void dispose() {
super.dispose();
}
void _removeTileOverlay() {
setState(() {
_tileOverlay = null;
});
}
void _addTileOverlay() {
final TileOverlay tileOverlay = TileOverlay(
tileOverlayId: TileOverlayId('tile_overlay_1'),
tileProvider: _DebugTileProvider(),
);
setState(() {
_tileOverlay = tileOverlay;
});
}
void _clearTileCache() {
if (_tileOverlay != null && controller != null) {
controller!.clearTileCache(_tileOverlay!.tileOverlayId);
}
}
@override
Widget build(BuildContext context) {
Set<TileOverlay> overlays = <TileOverlay>{
if (_tileOverlay != null) _tileOverlay!,
};
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Center(
child: SizedBox(
width: 350.0,
height: 300.0,
child: GoogleMap(
initialCameraPosition: const CameraPosition(
target: LatLng(59.935460, 30.325177),
zoom: 7.0,
),
tileOverlays: overlays,
onMapCreated: _onMapCreated,
),
),
),
TextButton(
child: const Text('Add tile overlay'),
onPressed: _addTileOverlay,
),
TextButton(
child: const Text('Remove tile overlay'),
onPressed: _removeTileOverlay,
),
TextButton(
child: const Text('Clear tile cache'),
onPressed: _clearTileCache,
),
],
),
);
}
}
class _DebugTileProvider implements TileProvider {
_DebugTileProvider() {
boxPaint.isAntiAlias = true;
boxPaint.color = Colors.blue;
boxPaint.strokeWidth = 2.0;
boxPaint.style = PaintingStyle.stroke;
}
static const int width = 100;
static const int height = 100;
static final Paint boxPaint = Paint();
static final TextStyle textStyle = TextStyle(
color: Colors.red,
fontSize: 20,
);
@override
Future<Tile> getTile(int x, int y, int? zoom) async {
final ui.PictureRecorder recorder = ui.PictureRecorder();
final Canvas canvas = Canvas(recorder);
final TextSpan textSpan = TextSpan(
text: '$x,$y',
style: textStyle,
);
final TextPainter textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout(
minWidth: 0.0,
maxWidth: width.toDouble(),
);
final Offset offset = const Offset(0, 0);
textPainter.paint(canvas, offset);
canvas.drawRect(
Rect.fromLTRB(0, 0, width.toDouble(), width.toDouble()), boxPaint);
final ui.Picture picture = recorder.endRecording();
final Uint8List byteData = await picture
.toImage(width, height)
.then((ui.Image image) =>
image.toByteData(format: ui.ImageByteFormat.png))
.then((ByteData? byteData) => byteData!.buffer.asUint8List());
return Tile(width, height, byteData);
}
}
TileOverlay is broken since version 2.0.0 of the google_maps_flutter plugin.
getTile function in the TileProvider implementation is never called.
I dug a bit deeper and found that the tileProvider inside the TileOverlay is considered null later on, even-though it was assigned with valid non-null TileProvider.
Nothing to indicate in the logs.
Steps to Reproduce
it was also broken in runtime, throwing
type '_CompactLinkedHashSet<TileOverlay?>' is not a subtype of type 'Set<TileOverlay>' in type castso i had to change it a little bit, see main.dart below.main.dart
Expected results: getTile should be called, following by a custom TileOverlay that should appear on the map.
Actual results: tileProvider is null, TileProvider.noTile is returned instead of Tile from getTile. Therefore nothing happens in the UI
flutter doctor -v
[✓] Flutter (Channel stable, 2.0.0, on macOS 11.2.2 20D80 darwin-x64, locale en-IL) • Flutter version 2.0.0 at /Users/myuser/development/flutter • Framework revision 60bd88df91 (4 days ago), 2021-03-03 09:13:17 -0800 • Engine revision 40441def69 • Dart version 2.12.0 [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3) • Android SDK at /Users/myuser/Library/Android/sdk • Platform android-S, build-tools 30.0.3 • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS • Xcode at /Applications/Xcode.app/Contents/Developer • Xcode 12.4, Build version 12D4e • CocoaPods version 1.10.1 [✓] Android Studio (version 4.1) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495) [✓] Connected device (1 available) • sdk gphone x86 64 (mobile) • emulator-5554 • android-x64 • Android 11 (API 30) (emulator) • No issues found! ` </details> <details> <summary>pubspec.yaml</summary> ` name: maps_test description: A new Flutter application. # The following line prevents the package from being accidentally published to # pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html version: 1.0.0+1 environment: sdk: ">=2.12.0 <3.0.0" dependencies: flutter: sdk: flutter google_maps_flutter: ^2.0.1 dev_dependencies: flutter_test: sdk: flutter # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: trueAfter clicking 'Add tile overlay':

Nothing happens:
