Google maps 如何在flatter中更改谷歌地图标记的图标大小?

Google maps 如何在flatter中更改谷歌地图标记的图标大小?,google-maps,flutter,dart,Google Maps,Flutter,Dart,我在我的Flitter应用程序中使用了google\u maps\u flatter来使用google map我有自定义标记图标,我用BitmapDescriptor.fromAsset(“images/car.png”)加载它,但是我在地图上的图标太大了,我想把它缩小,但我找不到任何选项,因为有任何选项可以更改自定义标记图标。 这是我的颤振代码: mapController.addMarker( MarkerOptions( icon: BitmapDesc

我在我的Flitter应用程序中使用了
google\u maps\u flatter
来使用google map我有自定义标记图标,我用
BitmapDescriptor.fromAsset(“images/car.png”)
加载它,但是我在地图上的图标太大了,我想把它缩小,但我找不到任何选项,因为有任何选项可以更改自定义标记图标。 这是我的颤振代码:

mapController.addMarker(
        MarkerOptions(
          icon: BitmapDescriptor.fromAsset("images/car.png"),

          position: LatLng(
            deviceLocations[i]['latitude'],
            deviceLocations[i]['longitude'],
          ),
        ),
      );
下面是我的android模拟器的屏幕截图:


正如您在图片中所看到的,我的自定义图标尺寸太大了,因此您可以尝试这种丑陋的方式。MediaQuery将返回比率并手动检查条件,如

 double mq = MediaQuery.of(context).devicePixelRatio;
 String icon = "images/car.png";
 if (mq>1.5 && mq<2.5) {icon = "images/car2.png";}
 else if(mq >= 2.5){icon = "images/car3.png";}
  mapController.addMarker(
    MarkerOptions(
       icon: BitmapDescriptor.fromAsset(icon),
       position: LatLng(37.4219999, -122.0862462),
     ),
   );

我发现解决这个问题的一个简单方法是

BitmapDescriptor get deliveryIcon {
  bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
  if (isIOS)
    return BitmapDescriptor.fromAsset('assets/icons/orange_pin.png');
  else
    return BitmapDescriptor.fromAsset(
        'assets/icons/3.0x/orange_pin.png');
} 

简单地说,为android提供更大的资源。

应避免使用大型图像,因为它们会消耗不必要的空间。应根据地图缩放图像,并根据设备的不同像素分辨率进行调整

例如,应将基础图像缩放到应用程序外部的正确大小。不同的设备有不同的像素分辨率,这正是flatter所能满足的。需要不同版本的图像,以便图像不会出现锯齿状。按不同分辨率放大图像。i、 e基本版本32x32像素,版本2.0将为64x64像素,版本3.0将为128x128等。请参阅下文所述的标准颤振方式,该方式可满足不同像素分辨率的要求,具体取决于设备制造商


BitmapDescriptor.fromAsset不支持像素分辨率的自动解码,将加载路径中指定的文件。要更正此调用,请使用AssetImage解码正确的文件名

图像呈现有一个bug,iOS中的图像看起来比Android大,请参见缺陷。这也有一个解决方法,通过硬编码您想要的解析的文件名

以下各节概述了标准颤振方式、AssetImage解决方案和24865解决方案

标准颤振图像命名约定

创建具有以下名称的资源文件夹:

其中M和N是分辨率(2.0x)或主题(暗)。 然后将图像或所有图像添加到pubspec.file中,如下所示:

flutter:
  assets:
    - pathtoimages/image.png

谷歌地图的解决方案

该标准要求使用AssetImages('pathtoimages/image.png')加载图像,这是google地图插件不支持的。Google maps要求您使用BitmapDescriptor.fromAsset('pathtoimages/image.png'),但此时无法解析为正确的图像。要解决此问题,您可以首先使用定义的BuildContext创建LocalimageConfiguration,从AssetImage获得正确的图像。然后使用此配置解析正确的图像,如下所示:

ImageConfiguration config = createLocalImageConfiguration(context);
AssetImage('pathtoimages/image.png')
   .obtainKey(config)
   .then((resolvedImage) {
       print('Name: ' + resolvedImage.onValue.name);
    });
缺陷解决方法

 BitmapDescriptor get deliveryIcon {
      bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
          If (isIOS)
              return BitmapDescriptor.fromAsset('pathtoimages/image.png');
         else
              return BitmapDescriptor.fromAsset(
              resolvedImageName);
    }
BitmapDescriptor.fromAsset()是添加标记的正确方法,只有一个打开的bug会影响代码。正如Saed所回答的,您需要为不同的设备屏幕密度提供不同大小的图像。根据您提供的图像,我猜您想要的图像的基本大小大约为48像素。因此,您需要制作大小为48、96(2.0x)和144(3.0x)的副本

运行时应根据屏幕密度选择正确的选项。看

目前,这并不是在Android或Fuschia上自动完成的。如果您现在正在发布并希望解决此问题,则可以使用以下逻辑检查平台:

    MediaQueryData data = MediaQuery.of(context);
    double ratio = data.devicePixelRatio;

    bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
如果平台不是iOS,您将在代码中实现bucket。将逻辑组合成一种方法:

String imageDir(String prefix, String fileName, double pixelRatio, bool isIOS) {
    String directory = '/';
    if (!isIOS) {
        if (pixelRatio >= 1.5) {
            directory = '/2.0x/';
        }
        else if (pixelRatio >= 2.5) {
            directory = '/3.0x/';
        }
        else if (pixelRatio >= 3.5) {
            directory = '/4.0x/';
        }
    }
    return '$prefix$directory$fileName';
}
然后,您可以使用以下代码为资产目录**assets/map_icons/**中名为person_icon的图标创建标记,方法如下:

            myLocationMarker = Marker(
            markerId: MarkerId('myLocation'),
            position: showingLocation, flat: true,
            icon: BitmapDescriptor.fromAsset(imageDir('assets/map_icons','person_icon.png', ratio, isIos)));

请尝试BitmapDescriptor.fromAssetImage。它也将忽略图像大小

BitmapDescriptor.fromAssetImage(
            ImageConfiguration(size: Size(32, 32)), 'assets/car.png')
        .then((onValue) {
      setState(() {
        markerIcon = onValue;
      });
    });
使用默认配置也会失败

loadMarkerImage(BuildContext context) {
    var config = createLocalImageConfiguration(context, size: Size(30, 30));
    BitmapDescriptor.fromAssetImage(config, 'assets/car.png')
        .then((onValue) {
      setState(() {
        markerIcon = onValue;
      });
    });
  }

是什么让我为不同的密度选择了正确的图像:

MediaQueryData mediaQueryData = MediaQuery.of(context);
ImageConfiguration imageConfig = ImageConfiguration(devicePixelRatio: mediaQueryData.devicePixelRatio);
BitmapDescriptor.fromAssetImage(imageConfig, "assets/images/marker.png");
TL;DR:只要您能够将任何图像编码为原始字节,如
Uint8List
,就可以将其用作标记


现在,您可以使用
Uint8List
数据使用谷歌地图创建标记。这意味着您可以使用原始数据绘制任何您想要的地图标记,只要您保持正确的编码格式(在这个特定场景中,它是
png

我将介绍两个示例,您可以选择:

  • 选择一个本地资源,动态地将其大小更改为您想要的大小,并在地图上渲染它(一个颤振徽标图像)
  • 在画布中绘制一些东西,并将其作为标记进行渲染,但这可以是任何渲染小部件
  • 除此之外,您甚至可以在静态图像中转换渲染小部件,并将其用作标记


    1.使用资产 首先,创建一个处理资源路径并接收大小的方法(可以是宽度、高度或两者,但只使用一个将保留比率)

    这将分别产生50、100和200宽度的以下结果


    2.使用画布 你可以用画布画任何你想画的东西,然后用它作为标记。下面将生成一个带有
    Hello world的简单圆形框其中的文本

    首先,用画布画一些东西:

    Future<Uint8List> getBytesFromCanvas(int width, int height) async {
      final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
      final Canvas canvas = Canvas(pictureRecorder);
      final Paint paint = Paint()..color = Colors.blue;
      final Radius radius = Radius.circular(20.0);
      canvas.drawRRect(
          RRect.fromRectAndCorners(
            Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
            topLeft: radius,
            topRight: radius,
            bottomLeft: radius,
            bottomRight: radius,
          ),
          paint);
      TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
      painter.text = TextSpan(
        text: 'Hello world',
        style: TextStyle(fontSize: 25.0, color: Colors.white),
      );
      painter.layout();
      painter.paint(canvas, Offset((width * 0.5) - painter.width * 0.5, (height * 0.5) - painter.height * 0.5));
      final img = await pictureRecorder.endRecording().toImage(width, height);
      final data = await img.toByteData(format: ui.ImageByteFormat.png);
      return data.buffer.asUint8List();
    }
    
    给你


    我也有同样的问题,我用这种方法解决

    Future < Uint8List > getBytesFromCanvas(int width, int height, urlAsset) async 
    {
        final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
        final Canvas canvas = Canvas(pictureRecorder);
        final Paint paint = Paint()..color = Colors.transparent;
        final Radius radius = Radius.circular(20.0);
        canvas.drawRRect(
            RRect.fromRectAndCorners(
                Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
                topLeft: radius,
                topRight: radius,
                bottomLeft: radius,
                bottomRight: radius,
            ),
            paint);
    
        final ByteData datai = await rootBundle.load(urlAsset);
    
        var imaged = await loadImage(new Uint8List.view(datai.buffer));
    
        canvas.drawImage(imaged, new Offset(0, 0), new Paint());
    
        final img = await pictureRecorder.endRecording().toImage(width, height);
        final data = await img.toByteData(format: ui.ImageByteFormat.png);
        return data.buffer.asUint8List();
    }
    
    Future < ui.Image > loadImage(List < int > img) async {
        final Completer < ui.Image > completer = new Completer();
        ui.decodeImageFromList(img, (ui.Image img) {
    
            return completer.complete(img);
        });
        return completer.future;
    }
    

    我已经更新了上面的功能,现在你可以根据自己的喜好缩放图像

      Future<Uint8List> getBytesFromCanvas(int width, int height, urlAsset) async {
        final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
        final Canvas canvas = Canvas(pictureRecorder);
    
        final ByteData datai = await rootBundle.load(urlAsset);
        var imaged = await loadImage(new Uint8List.view(datai.buffer));
        canvas.drawImageRect(
          imaged,
          Rect.fromLTRB(
              0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
          Rect.fromLTRB(0.0, 0.0, width.toDouble(), height.toDouble()),
          new Paint(),
        );
    
        final img = await pictureRecorder.endRecording().toImage(width, height);
        final data = await img.toByteData(format: ui.ImageByteFormat.png);
        return data.buffer.asUint8List();
      }
    
    Future getBytesFromCanvas(int-width、int-height、urlAsset)异步{
    final ui.PictureRecorder PictureRecorder=ui.PictureRecorder();
    最终画布=画布(pictureRecorder);
    final ByteData datai=等待rootBundle.load(urlAsset);
    var imaged=await loadImage(新的Uint8List.view(datai.buffer));
    canvas.drawImageRect(
    想象,
    Rect.fromLTRB(
    0.0,0.0,图像
    
    import 'dart:ui' as ui;
    
    Future<Uint8List> getBytesFromAsset(String path, int width) async {
      ByteData data = await rootBundle.load(path);
      ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
      ui.FrameInfo fi = await codec.getNextFrame();
      return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
    }
    
    final Uint8List markerIcon = await getBytesFromAsset('assets/images/flutter.png', 100);
    final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));
    
    Future<Uint8List> getBytesFromCanvas(int width, int height) async {
      final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
      final Canvas canvas = Canvas(pictureRecorder);
      final Paint paint = Paint()..color = Colors.blue;
      final Radius radius = Radius.circular(20.0);
      canvas.drawRRect(
          RRect.fromRectAndCorners(
            Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
            topLeft: radius,
            topRight: radius,
            bottomLeft: radius,
            bottomRight: radius,
          ),
          paint);
      TextPainter painter = TextPainter(textDirection: TextDirection.ltr);
      painter.text = TextSpan(
        text: 'Hello world',
        style: TextStyle(fontSize: 25.0, color: Colors.white),
      );
      painter.layout();
      painter.paint(canvas, Offset((width * 0.5) - painter.width * 0.5, (height * 0.5) - painter.height * 0.5));
      final img = await pictureRecorder.endRecording().toImage(width, height);
      final data = await img.toByteData(format: ui.ImageByteFormat.png);
      return data.buffer.asUint8List();
    }
    
    final Uint8List markerIcon = await getBytesFromCanvas(200, 100);
    final Marker marker = Marker(icon: BitmapDescriptor.fromBytes(markerIcon));
    
    Future < Uint8List > getBytesFromCanvas(int width, int height, urlAsset) async 
    {
        final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
        final Canvas canvas = Canvas(pictureRecorder);
        final Paint paint = Paint()..color = Colors.transparent;
        final Radius radius = Radius.circular(20.0);
        canvas.drawRRect(
            RRect.fromRectAndCorners(
                Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
                topLeft: radius,
                topRight: radius,
                bottomLeft: radius,
                bottomRight: radius,
            ),
            paint);
    
        final ByteData datai = await rootBundle.load(urlAsset);
    
        var imaged = await loadImage(new Uint8List.view(datai.buffer));
    
        canvas.drawImage(imaged, new Offset(0, 0), new Paint());
    
        final img = await pictureRecorder.endRecording().toImage(width, height);
        final data = await img.toByteData(format: ui.ImageByteFormat.png);
        return data.buffer.asUint8List();
    }
    
    Future < ui.Image > loadImage(List < int > img) async {
        final Completer < ui.Image > completer = new Completer();
        ui.decodeImageFromList(img, (ui.Image img) {
    
            return completer.complete(img);
        });
        return completer.future;
    }
    
    final Uint8List markerIcond = await getBytesFromCanvas(80, 98, urlAsset);
    
    setState(() {
    
        markersMap[markerId] = Marker(
            markerId: MarkerId("marker_${id}"),
            position: LatLng(double.parse(place.lat), double.parse(place.lng)),
    
            icon: BitmapDescriptor.fromBytes(markerIcond),
            onTap: () {
                _onMarkerTapped(placeRemote);
            },
    
        );
    });
    
      Future<Uint8List> getBytesFromCanvas(int width, int height, urlAsset) async {
        final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
        final Canvas canvas = Canvas(pictureRecorder);
    
        final ByteData datai = await rootBundle.load(urlAsset);
        var imaged = await loadImage(new Uint8List.view(datai.buffer));
        canvas.drawImageRect(
          imaged,
          Rect.fromLTRB(
              0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
          Rect.fromLTRB(0.0, 0.0, width.toDouble(), height.toDouble()),
          new Paint(),
        );
    
        final img = await pictureRecorder.endRecording().toImage(width, height);
        final data = await img.toByteData(format: ui.ImageByteFormat.png);
        return data.buffer.asUint8List();
      }
    
    Future<Uint8List> getBytesFromCanvas(double escala, urlAsset) async {
    
      final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
      final Canvas canvas = Canvas(pictureRecorder);
    
      final ByteData datai = await rootBundle.load(urlAsset);
      var imaged = await loadImage(new Uint8List.view(datai.buffer));
    
      double width = ((imaged.width.toDouble() * escala).toInt()).toDouble();
      double height = ((imaged.height.toDouble() * escala).toInt()).toDouble();
    
      canvas.drawImageRect(imaged, Rect.fromLTRB(0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
                                  Rect.fromLTRB(0.0, 0.0, width, height),
                                  new Paint(),
      );
    
      final img = await pictureRecorder.endRecording().toImage(width.toInt(), height.toInt());
      final data = await img.toByteData(format: ui.ImageByteFormat.png);
      return data.buffer.asUint8List();
    
    }
    
    Future < ui.Image > loadImage(List < int > img) async {
      final Completer < ui.Image > completer = new Completer();
      ui.decodeImageFromList(img, (ui.Image img) {
    
        return completer.complete(img);
      });
      return completer.future;
    }
    
    var iconTour;
    
    bool isIOS = Theme.of(context).platform == TargetPlatform.iOS;
    if (isIOS){
    
      final markerIcon = await getBytesFromCanvas(0.7, 'images/Icon.png');
      iconTour = BitmapDescriptor.fromBytes(markerIcon);
    
    }
    else{
    
      final markerIcon = await getBytesFromCanvas(1, 'images/Icon.png');
      iconTour = BitmapDescriptor.fromBytes(markerIcon);
    
    }
    
    setState(() {
      final Marker marker = Marker(icon: iconTour);
    });
    
     google_maps_flutter: ^0.5.19
    
    Future setMarkersPoint() async {
      var icon = 'your url';
      Uint8List dataBytes;
      var request = await http.get(icon);
      var bytes = await request.bodyBytes;
    
      setState(() {
        dataBytes = bytes;
      });
    
      final Uint8List markerIcoenter code heren =
          await getBytesFromCanvas(150, 150, dataBytes);
    
      var myLatLong = LatLng(double.parse(-6.9024812),
          double.parse(107.61881));
    
      _markers.add(Marker(
        markerId: MarkerId(myLatLong.toString()),
        icon: BitmapDescriptor.fromBytes(markerIcon),
        position: myLatLong,
       infoWindow: InfoWindow(
         title: 'Name of location',
        snippet: 'Marker Description',
       ),
      ));
    
    Future<Uint8List> getBytesFromCanvas(
      int width, int height, Uint8List dataBytes) async {
    final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
    final Canvas canvas = Canvas(pictureRecorder);
    final Paint paint = Paint()..color = Colors.transparent;
    final Radius radius = Radius.circular(20.0);
    canvas.drawRRect(
        RRect.fromRectAndCorners(
          Rect.fromLTWH(0.0, 0.0, width.toDouble(), height.toDouble()),
          topLeft: radius,
          topRight: radius,
          bottomLeft: radius,
          bottomRight: radius,
        ),
        paint);
    
    var imaged = await loadImage(dataBytes.buffer.asUint8List());
    canvas.drawImageRect(
      imaged,
      Rect.fromLTRB(
          0.0, 0.0, imaged.width.toDouble(), imaged.height.toDouble()),
      Rect.fromLTRB(0.0, 0.0, width.toDouble(), height.toDouble()),
      new Paint(),
    );
    
        final img = await pictureRecorder.endRecording().toImage(width, height);
        final data = await img.toByteData(format: ui.ImageByteFormat.png);
        return data.buffer.asUint8List();
     }
    
        Future<ui.Image> loadImage(List<int> img) async {
        final Completer<ui.Image> completer = new Completer();
        ui.decodeImageFromList(img, (ui.Image img) {
      return completer.complete(img);
    });
    return completer.future;
    }
    
    import 'dart:typed_data';
    import 'dart:ui' as ui;
    import 'package:flutter/services.dart';
    import 'package:flutter/material.dart';
    
    Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
    
    Future<Uint8List> getBytesFromAsset(String path, int width) async {
        ByteData data = await rootBundle.load(path);
        ui.Codec codec =
            await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
        ui.FrameInfo fi = await codec.getNextFrame();
        return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
       }
    
      Future<void> _addMarker(tmp_lat, tmp_lng) async {
        var markerIdVal = _locationIndex.toString();
        final MarkerId markerId = MarkerId(markerIdVal);
        final Uint8List markerIcon = await getBytesFromAsset('assets/img/pin2.png', 100);
    
        // creating a new MARKER
        final Marker marker = Marker(
          icon: BitmapDescriptor.fromBytes(markerIcon),
          markerId: markerId,
          position: LatLng(tmp_lat, tmp_lng),
          infoWindow: InfoWindow(title: markerIdVal, snippet: 'boop'),
        );
    
        setState(() {
          // adding a new marker to map
          markers[markerId] = marker;
        });
      }
    
    flutter:
    
      uses-material-design: true
    
      assets:
        - assets/img/pin1.png
        - assets/img/pin2.png
    
    images/car.png           <-- if this base image is 100x100px
    images/2.0x/car.png      <-- 2.0x one should be 200x200px
    images/3.0x/car.png      <-- and 3.0x one should be 300x300px
    
    mapController.addMarker(
            MarkerOptions(
              icon: BitmapDescriptor.fromAssetImage(
                      createLocalImageConfiguration(context),
                      "images/car.png"),
              position: LatLng(
                deviceLocations[i]['latitude'],
                deviceLocations[i]['longitude'],
              ),
            ),
          );
    
    import 'dart:ui' as ui;
    import 'dart:typed_data';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    
    
      Future<Uint8List> getBytesFromAsset(String path) async {
        double pixelRatio = MediaQuery.of(context).devicePixelRatio;
        ByteData data = await rootBundle.load(path);
        ui.Codec codec = await ui.instantiateImageCodec(
            data.buffer.asUint8List(),
            targetWidth: pixelRatio.round() * 30
        );
        ui.FrameInfo fi = await codec.getNextFrame();
        return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
      }
    
    
    final Uint8List markerIcon = await getBytesFromAsset('assets/images/bike.png');
    
    Marker(icon: BitmapDescriptor.fromBytes(markerIcon),)