Flutter 高德地圖之自定義Marks

image.png

高德地圖插件大家想必已經(jīng)不陌生了(不熟的去看上一篇),按產(chǎn)品需求開(kāi)發(fā)時(shí)需要在地圖上展示自定義的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,
    })

發(fā)現(xiàn)并沒(méi)有 Mark widget,沒(méi)有widget就意味著無(wú)法自定義widget,這可如何是好,但聰明的我又怎會(huì)被這小小的難題困住,百度、谷歌??疑難解答不懂就問(wèn)這是個(gè)好習(xí)慣,找到了解決思路,以BitmapDescriptor icon為突破口。

通過(guò)觀察BitmapDescriptor發(fā)現(xiàn)提供了展示png字節(jié)的方法:

static BitmapDescriptor fromBytes(Uint8List byteData) {
   return BitmapDescriptor._(<dynamic>['fromBytes', byteData]);
 }

至此是不是就明了了,只需將自定義的widget轉(zhuǎn)為png在轉(zhuǎn)為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拿走,多費(fèi)一點(diǎn)腦子算我輸,實(shí)現(xiàn)思路已OK

附上完整的代碼:

import 'dart:ui' as ui;
.
.
 AMapWidget? map;
 Map<String, Marker> initMarkerMap = <String, Marker>{};
 AMapController? _mapController;

 late BitmapDescriptor icon;

 ///自定義地圖mark的 widget轉(zhuǎn)字節(jié)
 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();
 }

如果到此處本文完結(jié)那和別的文章也就沒(méi)什么不同之處了,注意??有兩處坑

a.對(duì)于Text的定義要用

Directionality(
           textDirection: TextDirection.ltr,
           child:Text('')
        )

b.自定義的widget只能縱向布局因此可采用富文本來(lái)解決橫向布局需求 RichText()

====== 嫖走吧,有良心的就點(diǎn)點(diǎn)贊加個(gè)關(guān)注$$ =======

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容