I'm currently implementing a way to render my widgets that represents a Marker so I can then get an image of that widget using RepaintBoundary. It worked well, but then when I tried to use it inside the package google_maps_flutter, it seems like the package is shrinking my image by default.
The following picture contain my original widget and an instance of the GoogleMaps with a marker containing an image that was loaded using the BitmapDescriptor.fromBytes constructor. If I use something like Image.memory, the image renders correctly (the second image).

Code
MarkerGenerator (The code that I found. It will render a List of widgets and then return a equivalent List of Uint8List).
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class MarkerGenerator {
final Function(List<Uint8List>) callback;
final List<Widget> markerWidgets;
MarkerGenerator(this.markerWidgets, this.callback);
void generate(BuildContext context) {
WidgetsBinding.instance
.addPostFrameCallback((_) => afterFirstLayout(context));
}
void afterFirstLayout(BuildContext context) {
addOverlay(context);
}
void addOverlay(BuildContext context) {
final overlayState = Overlay.of(context);
late OverlayEntry entry;
entry = OverlayEntry(
builder: (context) {
return _MarkerHelper(
markerWidgets: markerWidgets,
callback: (List<Uint8List> bitmapList) {
callback.call(bitmapList);
entry.remove();
},
);
},
maintainState: true,
);
overlayState.insert(entry);
}
}
class _MarkerHelper extends StatefulWidget {
final List<Widget> markerWidgets;
final Function(List<Uint8List>) callback;
const _MarkerHelper({
required this.markerWidgets,
required this.callback,
});
@override
_MarkerHelperState createState() => _MarkerHelperState();
}
class _MarkerHelperState extends State<_MarkerHelper> with AfterLayoutMixin {
List<GlobalKey> globalKeys = [];
@override
void afterFirstLayout(BuildContext context) {
_getBitmaps(context).then((list) {
widget.callback(list);
});
}
@override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(MediaQuery.of(context).size.width, 0),
child: Material(
type: MaterialType.transparency,
child: Stack(
children: widget.markerWidgets.map((i) {
final markerKey = GlobalKey();
globalKeys.add(markerKey);
return RepaintBoundary(
key: markerKey,
child: i,
);
}).toList(),
),
),
);
}
Future<List<Uint8List>> _getBitmaps(BuildContext context) async {
final futures = globalKeys.map(_getUint8List);
return Future.wait(futures);
}
Future<Uint8List> _getUint8List(GlobalKey markerKey) async {
final boundary =
markerKey.currentContext?.findRenderObject() as RenderRepaintBoundary?;
if (boundary == null) {
return Uint8List(0);
}
final image = await boundary.toImage();
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData?.buffer.asUint8List() ?? Uint8List(0);
}
}
mixin AfterLayoutMixin<T extends StatefulWidget> on State<T> {
@override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => afterFirstLayout(context));
}
void afterFirstLayout(BuildContext context);
}
Then a method that will be something like this to transform the Uint8List to a list of Marker
List<Marker> mapBitmapsToMarkers(
List<Uint8List> bitmaps,
List<HMapPin> pins,
) {
final markersList = <Marker>[];
bitmaps.asMap().forEach((i, bmp) {
final pin = pins[i];
markersList.add(
Marker(
markerId: MarkerId(pin.point.toString()),
position: LatLng(pin.point.latitude, pin.point.longitude),
icon: BitmapDescriptor.fromBytes(bmp),
),
);
});
return markersList;
}
Then is just a normal usage of the package.
Thanks in advance.
