You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中使用PNG自定义图标时如何为谷歌地图标记设置自定义颜色

解决方案

核心实现逻辑:在原有尺寸调整逻辑的基础上,通过Canvas对解码后的PNG图片叠加颜色滤镜,即可在不新增多份资源文件的前提下实现自定义图标颜色,同时完全保留PNG本身的样式细节和透明度效果。


步骤1:修改getBytesFromAsset方法

新增着色参数,增加颜色滤镜绘制逻辑:

Future<Uint8List> getBytesFromAsset(String path, int width, {Color? tintColor}) async {
  ByteData data = await rootBundle.load(path);
  Codec codec = await instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
  FrameInfo fi = await codec.getNextFrame();
  
  // 未传入着色色值直接返回原图处理结果
  if (tintColor == null) {
    return (await fi.image.toByteData(format: ImageByteFormat.png)).buffer.asUint8List();
  }

  // 叠加颜色滤镜重新绘制图片
  final pictureRecorder = PictureRecorder();
  final canvas = Canvas(pictureRecorder);
  final paint = Paint()..colorFilter = ColorFilter.mode(tintColor, BlendMode.srcIn);
  canvas.drawImage(fi.image, Offset.zero, paint);
  final processedImage = await pictureRecorder.endRecording().toImage(width, fi.image.height);
  return (await processedImage.toByteData(format: ImageByteFormat.png)).buffer.asUint8List();
}

步骤2:方法调用示例

调用时传入对应的颜色参数即可生成对应色调的图标,你甚至可以只保留1份基础PNG资源,通过不同参数生成所有需要的图标:

// 生成100尺寸的蓝色图标
final Uint8List plannedIcon = await getBytesFromAsset('assets/base_marker.png', 100, tintColor: Colors.blue);
// 生成100尺寸的绿色图标
final Uint8List doneIcon = await getBytesFromAsset('assets/base_marker.png', 100, tintColor: Colors.green);
// 生成80尺寸的灰色图标
final Uint8List blankIcon = await getBytesFromAsset('assets/base_marker.png', 80, tintColor: Colors.grey);

完整修改后的updateMarkers参考代码

void updateMarkers(List<Place> placeList) async {
  // 仅需1份PNG资源,通过参数控制尺寸和颜色
  final Uint8List plannedIcon = await getBytesFromAsset('assets/base_marker.png', 100, tintColor: Colors.blue);
  final Uint8List doneIcon = await getBytesFromAsset('assets/base_marker.png', 100, tintColor: Colors.green);
  final Uint8List blankIcon = await getBytesFromAsset('assets/base_marker.png', 100, tintColor: Colors.grey);

  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;
      }
    });
  });
}

注意事项

  • 方案中使用的BlendMode.srcIn模式会保留原图的透明度信息,仅替换不透明区域的颜色,完美适配带透明背景的PNG图标
  • 如果你需要保留PNG本身的部分颜色仅调整整体色调,可以更换BlendMode枚举值,例如BlendMode.modulate可实现自然的颜色叠加效果
  • 性能优化建议:可以将生成好的不同尺寸、颜色的图标字节缓存起来,避免重复绘制消耗性能

内容的提问来源于stack exchange,提问作者Justin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:36:03