Creating Custom Markers in Flutter: A Comprehensive Guide (Widget to custom marker).
Introduction
Flutter is a versatile framework for building natively compiled applications for mobile, web, and desktop from a single codebase. When it comes to building location-based applications, such as maps, custom markers can enhance the user experience significantly. In this guide, we will explore how to generate custom markers in Flutter, giving you the ability to personalize your map-based applications.
Why Custom Markers?
Custom markers allow you to replace the default map pins with icons, images, or any other widget you desire. Whether you want to show specific landmarks, highlight important locations, or just add a touch of personalization to your map, custom markers can make your Flutter app stand out.
Getting Started
To create custom markers in Flutter, you’ll need to use the google_maps_flutter
package. Start by adding this package to your pubspec.yaml
dependencies:
flutter:
sdk: flutter
google_maps_flutter: ^2.0.10
Run flutter pub get
to fetch the package.
Creating Custom Marker:
Create one file named widget_to_map_icon.dart
copy below content to that file
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
extension ToBitDescription on Widget {
Future<BitmapDescriptor> toBitmapDescriptor({Size? logicalSize, Size? imageSize, Duration waitToRender = const Duration(milliseconds: 300), TextDirection textDirection = TextDirection.ltr}) async {
final widget = RepaintBoundary(
child: MediaQuery(data: const MediaQueryData(), child: Directionality(textDirection: TextDirection.ltr, child: this)),
);
final pngBytes = await createImageFromWidget(widget, waitToRender: waitToRender, logicalSize: logicalSize, imageSize: imageSize);
return BitmapDescriptor.fromBytes(pngBytes);
}
}
/// Creates an image from the given widget by first spinning up a element and render tree,
/// wait [waitToRender] to render the widget that take time like network and asset images
/// The final image will be of size [imageSize] and the the widget will be layout, ... with the given [logicalSize].
/// By default Value of [imageSize] and [logicalSize] will be calculate from the app main window
Future<Uint8List> createImageFromWidget(Widget widget, {Size? logicalSize, required Duration waitToRender, Size? imageSize}) async {
final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
final view = ui.PlatformDispatcher.instance.views.first;
logicalSize ??= view.physicalSize / view.devicePixelRatio;
imageSize ??= view.physicalSize;
// assert(logicalSize.aspectRatio == imageSize.aspectRatio);
final RenderView renderView = RenderView(
view: view,
child: RenderPositionedBox(alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration(
size: logicalSize,
devicePixelRatio: 1.0,
),
);
final PipelineOwner pipelineOwner = PipelineOwner();
final BuildOwner buildOwner = BuildOwner(focusManager: FocusManager());
pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame();
final RenderObjectToWidgetElement<RenderBox> rootElement = RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary,
child: widget,
).attachToRenderTree(buildOwner);
buildOwner.buildScope(rootElement);
await Future.delayed(waitToRender);
buildOwner.buildScope(rootElement);
buildOwner.finalizeTree();
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
final ui.Image image = await repaintBoundary.toImage(pixelRatio: imageSize.width / logicalSize.width);
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
return byteData!.buffer.asUint8List();
}
Google map always need marker type as a BitmapDescriptor.
So convert widget in to BitmapDescriptor. just add extention to that marker like below.
Future<BitmapDescriptor> getCustomIcon() async {
return SizedBox(
height: 200,
width: 200,
child: Image.asset("temp image"),
).toBitmapDescriptor();
}
Make an marker list like below
List<Marker> markerList = <Marker>[];
markerList.add(
Marker(
markerId: const MarkerId("MarkerId"),
position: LatLng(21.000000, 72.000000),
icon: await getCustomIcon(),
),
)
Now finally, Use this marker list as below to show custom marker in google map.
GoogleMap(
mapType: MapType.hybrid,
arkers: markerList.toSet()
initialCameraPosition: _kGooglePlex,
onMapCreated: (GoogleMapController controller) {
_controller.complete(controller);
},
)
Output will look like :-
Conclusion
In this guide, we’ve walked through the process of creating custom markers in Flutter for Google Maps. By following these steps, you can enhance your map-based applications with personalized markers that cater to your specific needs.
Custom markers are a powerful tool in Flutter, allowing you to create visually appealing and informative maps for your users. Experiment with different marker designs and see how they can elevate your Flutter applications to the next level. Happy coding!