在 flutter 中,有一种方法可以使用 png 中的自定义图标为 google 地图标记设置自定义颜色

In flutter is there a way to set a custom color for a google maps marker using a custom icon from a png

在 flutter 中使用 google 地图尝试使用具有自定义颜色和大小的 .png 图像放置标记。除了自定义颜色,我什么都可以用,只是无法弄清楚如何在没有多个图像资产都具有不同颜色的情况下进行操作。

我正在使用存储为资产的 .png 文件,并使用一些编解码器和 frameinfo 转换为字节并操纵大小。我也无法操纵颜色。我看过设置基本标记颜色的示例,但我无法指定图标。我看过使用 canvas 构建自己的带有形状的图标的示例,但这不允许我使用 png 作为我的图标(具有更多格式的好处)。

我正在尝试获取自定义图标和具有自定义大小的自定义颜色。

代码看起来有点像这样:

import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'dart:ui';

class ExplorePage extends StatefulWidget {
  @override
  ExplorePageState createState() => ExplorePageState();
}

class ExplorePageState extends State<ExplorePage> {
  final Map<String, Marker> markers = {};
  StreamSubscription placeSubscription;
  final LatLng center = const LatLng(37.6872, -97.3301);

  void updateLists(List<PlaceList> PlaceList) async {
    setState(() {
      listPlaceList = PlaceList;
    });
  }

  //called when the map is done being created
  void onMapCreated(GoogleMapController controller) {
    placeSubscription = placesBloc
        .getPlaces()
        //when the data changes update the map
        .listen(updateMarkers);
  }

  //gets called when the data or filter changes, updates the markers list that is tied
  //to the map and sets state so the map loads the markers
  void updateMarkers(List<Place> placeList) async {
    
final Uint8List plannedIcon =
        await getBytesFromAsset('assets/planned_marker.png', 100);
    final Uint8List doneIcon =
        await getBytesFromAsset('assets/done_marker.png', 100);
    final Uint8List blankIcon =
        await getBytesFromAsset('assets/blank_marker.png', 100);

    setState(() {
      placeList.forEach((Place place) {
        if (place.latlon != null) {
          final marker = Marker(
            markerId: MarkerId(place.docId),
            icon: place.done == null
                ? BitmapDescriptor.fromBytes(blankIcon)
                : place.done == 'Done!'
                    ? BitmapDescriptor.fromBytes(doneIcon)
                    : place.done == 'Planned'
                        ? BitmapDescriptor.fromBytes(plannedIcon)
                        : BitmapDescriptor.fromBytes(blankIcon),
            position: LatLng(place.latlon.latitude, place.latlon.longitude),
            infoWindow: InfoWindow(
              title: place.name,
              snippet: place.name,
            ),
          );
          markers[place.name] = marker;
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
 
    return Scaffold(
        body: Stack(
      children: [
        GoogleMap(
          zoomGesturesEnabled: true,
          myLocationButtonEnabled: false,
          onMapCreated: onMapCreated,
          markers: markers.values.toSet(),
          initialCameraPosition: CameraPosition(
            target: center,
            zoom: 5.0,
          ),
        ),
        
      ],
    ));
  }

  Future<Uint8List> getBytesFromAsset(String path, int width) async {
    ByteData data = await rootBundle.load(path);
    Codec codec = await instantiateImageCodec(data.buffer.asUint8List(),
        targetWidth: width);
    FrameInfo fi = await codec.getNextFrame();
        
    return (await fi.image.toByteData(format: ImageByteFormat.png))
        .buffer
        .asUint8List();
  }
}

要自定义标记,您需要使用:BitmapDescriptor,我们可以使用构造函数创建此对象:BitmapDescriptor.fromBytes()。您的问题是如何从您的 png 和动态颜色创建 Uint8List

要解决问题,您可以尝试支持将位图编辑为 image 的程序包,或者创建您的 canvas 来绘制图像,编辑并导出到 Uint8List。不过我推荐第一种方式。

采用了 dangngocduc 使用链接图像库建议的方法。这是我的语法最终如何使用资产图像。偏移最终成为调整颜色的最佳设置(我尝试了很多)。由于它锚定到图像上的起始颜色,我将基本照片转换为黑色默认颜色(否则我无法完全控制生成的颜色)。

YAML 依赖性

  image: ^3.0.8

导入语句

import 'package:image/image.dart' as img;

以资产 png 开始并生成用于标记的 BitmapDescriptor 的代码

ByteData donebytes = await rootBundle.load('assets/done_marker.png');
Uint8List doneU8 = donebytes.buffer
    .asUint8List(donebytes.offsetInBytes, donebytes.lengthInBytes);
List<int> doneListInt = doneU8.cast<int>();

img.Image doneImg = img.decodePng(doneListInt);

img.colorOffset(
  doneImg,
  red: 0,
  green: 0,
  blue: 250,
);


doneImg = img.copyResize(doneImg, width: 100);

final Uint8List doneIconColorful =
    Uint8List.fromList(img.encodePng(doneImg)); //doneImg.getBytes();
BitmapDescriptor doneBM = BitmapDescriptor.fromBytes(doneIconColorful);