高德地图插件大家想必已经不陌生了(不熟的去看上一篇),按产品需求开发时需要在地图上展示自定义的Mark,观察Mark方法:
(new) Marker Marker({ required LatLng position, double alpha = 1.0, Offset anchor = const Offset(0.5, 1.0), bool clickable = true, bool draggable = false, BitmapDescriptor icon = BitmapDescriptor.defaultMarker, bool infoWindowEnable = true, InfoWindow infoWindow = InfoWindow.noText, double rotation = 0.0, bool visible = true, double zIndex = 0.0, void Function(String)? onTap, void Function(String, LatLng)? onDragEnd, })
发现并没有 Mark widget,没有widget就意味着无法自定义widget,这可如何是好,但聪明的我又怎会被这小小的难题困住,百度、谷歌😁疑难解答不懂就问这是个好习惯,找到了解决思路,以BitmapDescriptor icon为突破口。
通过观察BitmapDescriptor发现提供了展示png字节的方法:
static BitmapDescriptor fromBytes(Uint8List byteData) { return BitmapDescriptor._(<dynamic>['fromBytes', byteData]); }
至此是不是就明了了,只需将自定义的widget转为png在转为ByteData即可。
wiget->ByteData:
Future<ByteData?> widgetToByteData(Widget widget, {Alignment alignment = Alignment.center, Size size = const Size(double.maxFinite, double.maxFinite), double devicePixelRatio = 1.0, double pixelRatio = 1.0}) async { RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary(); RenderView renderView = RenderView( child: RenderPositionedBox(alignment: alignment, child: repaintBoundary), configuration: ViewConfiguration( size: size, devicePixelRatio: devicePixelRatio, ), window: ui.window, ); PipelineOwner pipelineOwner = PipelineOwner(); pipelineOwner.rootNode = renderView; renderView.prepareInitialFrame(); BuildOwner buildOwner = BuildOwner(focusManager: FocusManager()); RenderObjectToWidgetElement rootElement = RenderObjectToWidgetAdapter( container: repaintBoundary, child: widget, ).attachToRenderTree(buildOwner); buildOwner.buildScope(rootElement); buildOwner.finalizeTree(); pipelineOwner.flushLayout(); pipelineOwner.flushCompositingBits(); pipelineOwner.flushPaint(); ui.Image image = await repaintBoundary.toImage(pixelRatio: pixelRatio); ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); return byteData; }
此方法直接copy拿走,多费一点脑子算我输,实现思路已OK
附上完整的代码:
import 'dart:ui' as ui; . . AMapWidget? map; Map<String, Marker> initMarkerMap = <String, Marker>{}; AMapController? _mapController; late BitmapDescriptor icon; ///自定义地图mark的 widget转字节 Future<ByteData?> widgetToByteData(Widget widget, {Alignment alignment = Alignment.center, Size size = const Size(double.maxFinite, double.maxFinite), double devicePixelRatio = 1.0, double pixelRatio = 1.0}) async { RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary(); RenderView renderView = RenderView( child: RenderPositionedBox(alignment: alignment, child: repaintBoundary), configuration: ViewConfiguration( size: size, devicePixelRatio: devicePixelRatio, ), window: ui.window, ); PipelineOwner pipelineOwner = PipelineOwner(); pipelineOwner.rootNode = renderView; renderView.prepareInitialFrame(); BuildOwner buildOwner = BuildOwner(focusManager: FocusManager()); RenderObjectToWidgetElement rootElement = RenderObjectToWidgetAdapter( container: repaintBoundary, child: widget, ).attachToRenderTree(buildOwner); buildOwner.buildScope(rootElement); buildOwner.finalizeTree(); pipelineOwner.flushLayout(); pipelineOwner.flushCompositingBits(); pipelineOwner.flushPaint(); ui.Image image = await repaintBoundary.toImage(pixelRatio: pixelRatio); ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png); return byteData; } ///自定义widget widgetContext( ) { return Container( width: 540.w, height: 180.h, decoration: BoxDecoration( border: Border.all(width: 5.w, color: Color.fromRGBO(236, 253, 255, 1)), color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(70.r), topRight: Radius.circular(70.r), bottomRight: Radius.circular(70.r), bottomLeft: Radius.circular(12.r))), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ··· ], ), ); } ///添加自定义mark addMark() async { ByteData? byteData = await widgetToByteData(widgetContext()); icon = BitmapDescriptor.fromBytes(byteData!.buffer.asUint8List()); Marker marker = Marker( infoWindowEnable: false, position: LatLng(double.parse(item['lat'].toString()), double.parse(item['lng'].toString())), icon: icon, anchor: const Offset(0, 1.0), ); initMarkerMap[marker.id] = marker; } setState(() { map = AMapWidget( mapType: MapType.bus, labelsEnabled: false, onLocationChanged: (argument) { onLocationChangeds(argument); }, myLocationStyleOptions: MyLocationStyleOptions(false), privacyStatement: AmapConfig.amapPrivacyStatement, apiKey: AmapConfig.amapApiKeys, onMapCreated: onMapCreated, markers: Set<Marker>.of(initMarkerMap.values), ); }); } @override void initState() { // TODO: implement initState super.initState(); addMark(); }
如果到此处本文完结那和别的文章也就没什么不同之处了,注意⚠️有两处坑
a.对于Text的定义要用
Directionality( textDirection: TextDirection.ltr, child:Text('') )
b.自定义的widget只能纵向布局因此可采用富文本来解决横向布局需求 RichText()
====== 嫖走吧,有良心的就点点赞加个关注$$ =======
Flutter 高德地图之自定义Marks
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- Flutter提供了一个RepaintBoundaryWidget来实现截图的功能,用RepaintBoundar...
- 邂逅FLutter 万物皆是Widget 一般缩进2个空格 文字居中 Widget Center() Materi...
- 最近接到了一个新需求 计划做路线提示 由于个性化程度很高 与原地图差异较大 我选择了自定义地图和路线规划相机和的方...
- 本文将对Framework 的 Widget 、BuildOwner 、Element 、PaintingCont...