Skip to content

Instantly share code, notes, and snippets.

@sahildev001
Created March 29, 2023 11:48
Show Gist options
  • Save sahildev001/b40ab9c9bc3e836340c5a10a0021f6e1 to your computer and use it in GitHub Desktop.
Save sahildev001/b40ab9c9bc3e836340c5a10a0021f6e1 to your computer and use it in GitHub Desktop.
This Will generate markers from widget.
static Widget customNumberMarker(String number) {
return Container(
alignment: Alignment.bottomCenter,
height: 100,
width: 100,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Container(
height: 150,
width: 150,
alignment: Alignment.center,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
border: Border.all(color: Colors.black)
),
child: Text(number,
style: const TextStyle(
fontSize: 50
),),
),
const SizedBox(
height: 70,
child: VerticalDivider(width: 1,color: Colors.black,),
),
Container(
height: 20,
width: 20,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.black
),
)
],
),
);
}
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'package:flutter/rendering.dart';
import 'dart:ui' as ui;
import 'package:flutter/scheduler.dart';
class MapMarkerGeneratorFromWidget {
final Function(Uint8List) callback;
final Widget markerWidgets;
MapMarkerGeneratorFromWidget(this.markerWidgets, this.callback);
void generate(BuildContext context) {
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) {
SchedulerBinding.instance.addPostFrameCallback((_) => afterFirstLayout(context));
} else {
afterFirstLayout(context);
}
}
void afterFirstLayout(BuildContext context) {
addOverlay(context);
}
void addOverlay(BuildContext context) {
OverlayState overlayState = Overlay.of(context)!;
OverlayEntry entry = OverlayEntry(
builder: (context) {
return _MarkerHelper(
markerWidgets: markerWidgets,
callback: callback,
);
},
maintainState: true);
overlayState.insert(entry);
}
}
///
/// Maps are embeding GoogleMap library for Andorid/iOS into flutter.
///
/// These native libraries accept BitmapDescriptor for marker, which means that for custom markers
/// you need to draw view to bitmap and then send that to BitmapDescriptor.
///
/// Because of that Flutter also cannot accept Widget for marker, but you need draw it to bitmap and
/// that's what this widget does:
///
/// 1) It draws marker widget to tree
/// 2) After painted access the repaint boundary with global key and converts it to uInt8List
/// 3) Returns set of Uint8List (bitmaps) through callback
class _MarkerHelper extends StatefulWidget {
final Widget markerWidgets;
final Function(Uint8List) callback;
const _MarkerHelper({Key? key,required this.markerWidgets,required this.callback})
: super(key: key);
@override
_MarkerHelperState createState() => _MarkerHelperState();
}
class _MarkerHelperState extends State<_MarkerHelper> with AfterLayoutMixin {
late GlobalKey globalKeys;
@override
void afterFirstLayout(BuildContext context) {
_getBitmaps(context).then((list) {
widget.callback(list);
});
}
@override
Widget build(BuildContext context) {
final markerKey = GlobalKey();
globalKeys = markerKey;
return Transform.translate(
offset: Offset(MediaQuery.of(context).size.width, 0),
child: Material(
type: MaterialType.transparency,
child: RepaintBoundary(
key: markerKey,
child: widget.markerWidgets,
),
),
);
}
Future<Uint8List> _getBitmaps(BuildContext context) async {
var futures = _getUint8List(globalKeys);
return futures;
}
Future<Uint8List> _getUint8List(GlobalKey markerKey) async {
RenderRepaintBoundary boundary =
markerKey.currentContext!.findRenderObject() as RenderRepaintBoundary ;
print("Boundary constraints: ${boundary.constraints}");
// boundary.layout(BoxConstraints(maxWidth: 360, maxHeight: 360, minWidth: 360, minHeight: 360), parentUsesSize: true);
print("Boundary constraints after changing: ${boundary.constraints}");
var image = await boundary.toImage(pixelRatio: .55);
ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData!.buffer.asUint8List();
}
}
/// AfterLayoutMixin
mixin AfterLayoutMixin<T extends StatefulWidget> on State<T> {
@override
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => afterFirstLayout(context));
}
void afterFirstLayout(BuildContext context);
}
// Use this class as
MapMarkerGeneratorFromWidget(CommonMethods.customNumberMarker("${i+1}"), (bitmaps) {
setState(() {
BitmapDescriptor icon = BitmapDescriptor.fromBytes(bitmaps);
dev.log("$TAG icon :-- $icon");
if(updatedOrders[i].addressDelivery?.latLng != null) {
LatLng markerLatLng = LatLng(
(updatedOrders[i].addressDelivery?.latLng?.latitude ?? 0.0)
.toDouble(),
(updatedOrders[i].addressDelivery?.latLng?.longitude ?? 0.0)
.toDouble(),
);
markers.add(
Marker(
markerId: MarkerId(i.toString()),
position: markerLatLng,
icon: icon
)
);
}
if(orders[i].addressDelivery?.latLng != null) {
LatLng polyLatLng = LatLng(
(orders[i].addressDelivery?.latLng?.latitude ?? 0.0).toDouble(),
(orders[i].addressDelivery?.latLng?.longitude ?? 0.0).toDouble(),
);
polyLineLatLngList.add(polyLatLng);
}
getDirections(polyLineLatLngList);
});
}).generate(context);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment