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

Flutter Web地图标记图片加载失败:意外空值错误

Flutter Web中MapLibre GL自定义标记加载成功但无法显示,addSymbol抛出Unexpected null value异常

环境详情

  • Flutter版本:3.5.4
  • 依赖配置:
dependencies:
   flutter:
       sdk: flutter
   flutter_radar: ^3.12.3
   flutter_map: ^5.0.0
   latlong2: ^0.9.0
   cupertino_icons: ^1.0.8
   http: ^1.2.2
   http_client: ^1.5.3
   vector_map_tiles: ^6.0.2
   maplibre_gl: ^0.20.0
  • pubspec.yaml资源配置:
flutter:
  assets:
    - images/marker.png
  • 图片路径:project/images/marker.png

代码实现

以下是onMapCreated函数及加载标记的辅助方法:

import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:maplibre_gl/maplibre_gl.dart';

Future<void> _onMapCreated(MapLibreMapController controller) async {
  print('[DEBUG] Entering _onMapCreated');
  try {
    const imagePath = 'images/marker.png';
    print('[DEBUG] Loading marker image from path: $imagePath');

    final Uint8List markerImage = await _loadMarkerImage(imagePath);
    print('[DEBUG] Marker image loaded successfully');

    await controller.addImage('marker', markerImage);
    print('[DEBUG] Marker image added to map');

    const markerPosition = LatLng(40.7342891, -73.9910334);
    print('[DEBUG] Adding marker at: ${markerPosition.latitude}, ${markerPosition.longitude}');
    await controller.addSymbol(
      SymbolOptions(
        geometry: markerPosition,
        iconImage: 'marker',
        iconSize: 1.0,
      ),
    );
    print('[DEBUG] Marker added successfully');
  } catch (e, stackTrace) {
    print('[ERROR] Exception in _onMapCreated: $e');
    print(stackTrace);
  }
}

Future<Uint8List> _loadMarkerImage(String path) async {
  print('[DEBUG] Loading image from path: $path');
  try {
    final ByteData data = await rootBundle.load(path);
    print('[DEBUG] Image loaded from assets: $path');
    return data.buffer.asUint8List();
  } catch (e) {
    print('[ERROR] Failed to load marker image from path: $path');
    throw Exception('[ERROR] Asset not found or invalid: $path');
  }
}

日志信息

图片加载成功,但标记未添加到地图,日志如下:

1736194029179 [stdout] [DEBUG] Map created successfully
1736194029179 [stdout] [DEBUG] Entering _onMapCreated
1736194029179 [stdout] [DEBUG] Loading marker image
1736194029179 [stdout] [DEBUG] Entering _loadMarkerImage
1736194029180 [stdout] [DEBUG] Loading image from path: packages/portal_package/assets/images/marker.png
1736194029255 [stdout] [DEBUG] Image loaded from assets: packages/portal_package/assets/images/marker.png
1736194029255 [stdout] [DEBUG] Marker image loaded successfully
1736194029255 [stdout] [DEBUG] Adding marker image to map
1736194029262 [stdout] [DEBUG] Marker image added to map
1736194029262 [stdout] [DEBUG] Adding marker symbol to map at: 40.7342891, -73.9910334
1736194029263 [stdout] [ERROR] Exception in _onMapCreated: Unexpected null value.

已尝试的解决方法

  • 确认images/marker.png文件存在且与pubspec.yaml路径一致;
  • 执行flutter clean和flutter pub get重建项目;
  • 验证_loadMarkerImage步骤中图片加载成功;
  • 测试flutter run -d chrome和生产构建flutter build web。

问题

图片加载成功但标记仍不显示,如何修复addSymbol步骤中的Unexpected null value异常?


解决方案

1. 适配Web端图片加载逻辑

MapLibre GL在Web端对Uint8List格式的图片兼容性有限,改用HTML原生API加载图片后再转成Uint8List:

import 'dart:typed_data';
import 'dart:html' as html;
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

Future<Uint8List> _loadMarkerImage(String path) async {
  if (kIsWeb) {
    final img = html.HtmlImageElement();
    // Web端资源路径修正:pubspec配置的images/marker.png对应打包后的assets/images/marker.png
    img.src = 'assets/$path';
    await img.onLoad.first;
    
    final canvas = html.CanvasElement(width: img.width, height: img.height);
    final ctx = canvas.context2D;
    ctx.drawImage(img, 0, 0);
    final blob = await canvas.toBlob('image/png');
    return Uint8List.fromList(await blob!.arrayBuffer());
  } else {
    final ByteData data = await rootBundle.load(path);
    return data.buffer.asUint8List();
  }
}

2. 等待地图完全初始化

onMapCreated触发时地图可能未完全加载完成,等待地图进入空闲状态后再添加标记:

Future<void> _onMapCreated(MapLibreMapController controller) async {
  print('[DEBUG] Entering _onMapCreated');
  try {
    // 等待地图空闲状态(资源加载完成)
    await controller.onMapIdle.first;
    
    // 后续图片加载和标记添加逻辑保持不变
    const imagePath = 'images/marker.png';
    print('[DEBUG] Loading marker image from path: $imagePath');

    final Uint8List markerImage = await _loadMarkerImage(imagePath);
    print('[DEBUG] Marker image loaded successfully');

    await controller.addImage('marker', markerImage);
    print('[DEBUG] Marker image added to map');

    const markerPosition = LatLng(40.7342891, -73.9910334);
    print('[DEBUG] Adding marker at: ${markerPosition.latitude}, ${markerPosition.longitude}');
    await controller.addSymbol(
      SymbolOptions(
        geometry: markerPosition,
        iconImage: 'marker',
        iconSize: 1.0,
      ),
    );
    print('[DEBUG] Marker added successfully');
  } catch (e, stackTrace) {
    print('[ERROR] Exception in _onMapCreated: $e');
    print(stackTrace);
  }
}

3. 升级MapLibre GL包版本

当前使用的maplibre_gl: ^0.20.0版本存在Web端已知兼容性问题,升级到最新稳定版本(如^0.26.0):
修改pubspec.yaml:

dependencies:
  # ...其他依赖
  maplibre_gl: ^0.26.0

执行flutter pub upgrade maplibre_gl更新依赖。

4. 修正Package资源路径(若项目为Package)

日志显示图片路径为packages/portal_package/assets/images/marker.png,说明当前项目是Package,需修正图片路径和pubspec配置:

  • 代码中路径改为:
const imagePath = 'packages/portal_package/images/marker.png';
  • pubspec.yaml资源配置改为:
flutter:
  assets:
    - packages/portal_package/images/marker.png

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:09:58