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
相关产品推荐
相关产品推荐

