skip to Main Content

Body:

I’m working on a Flutter app that uses the maplibre_gl and flutter radar packages to display a map. (https://radar.com/documentation/tutorials/displaying-radar-maps-with-flutter) I want to add a custom marker to the map using an image stored in the images folder in the root directory. I’ve added the image path to the pubspec.yaml file, and the marker image loads without any errors in development mode. However, the marker doesn’t appear on the map after the flutter run -d chrome. Below are the details and the relevant logs.

Environment Details:

  • Flutter version: 3.5.4
  • Dependencies:
    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
    
  • Asset Configuration in pubspec.yaml:
    flutter:
      assets:
        - images/marker.png
    
  • Image Path:
    I’ve placed the marker image in:

    project/images/marker.png
    

Code Implementation:

Here’s my onMapCreated function and helper methods to load the marker:

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

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

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

    // Add a marker to the map
    const markerPosition = LatLng(40.7342891, -73.9910334); // Marker position
    print('[DEBUG] Adding marker at: ${markerPosition.latitude}, ${markerPosition.longitude}');
    await controller.addSymbol(
      SymbolOptions(
        geometry: markerPosition,
        iconImage: 'marker', // Matches the key used in addImage()
        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');
  }
}

What I See in the Logs:

Despite the image being loaded successfully, the marker isn’t added to the map, and I get the following logs:

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.

What I’ve Tried:

  1. Ensured the images/marker.png file exists in the root directory and matches the path in pubspec.yaml.
  2. Confirmed the asset was declared correctly in pubspec.yaml and rebuilt the project (flutter clean and flutter pub get).
  3. Verified the image loads successfully during the _loadMarkerImage step.
  4. Tested with both flutter run -d chrome and the production build (flutter build web).

Expected Behavior:

The marker image should display on the map.


Question:

Why is the marker not appearing on the map even though the image loads successfully? How can I fix the Unexpected null value exception in the addSymbol step?

2

Answers


  1. Ok, I looked into the maplibre_gl package. All the examples in the docs are adding the symbols in the onStyleLoadedCallback callback and not in the onMapCreated.

    Take a look at this MapLibreMap class documetation. Even here it is suggested You should only add annotations (e.g. symbols or circles) after onStyleLoadedCallback has been called.

    So you should add the custom marker symbol in the onStyleLoadedCallback callback.

    The Radar documentation you pointed may be wrong in adding the Symbol in onMapCreated callback.

    Further reference: Check this Github comment

    Login or Signup to reply.
  2. It appears the error happens during the addSymbol step despite image loading successfully. Use the implementation below which includes error handling and logging:

    import 'package:flutter/services.dart';
    import 'package:maplibre_gl/maplibre_gl.dart';
    import 'dart:typed_data';
    
    class MapMarkerManager {
      static const double DEFAULT_ICON_SIZE = 0.5;
      static const String DEFAULT_ICON_NAME = 'custom-marker';
      
      final MapLibreMapController controller;
      
      MapMarkerManager(this.controller);
    
      /// Adds a marker to the map with comprehensive error handling
      Future<void> addMarkerToMap({
        required String imagePath,
        required LatLng position,
        String? iconName,
        double iconSize = DEFAULT_ICON_SIZE,
        double? iconRotation,
      }) async {
        final String markerIconName = iconName ?? DEFAULT_ICON_NAME;
        
        try {
          // Step 1: Load and validate the image
          final Uint8List? imageData = await _loadAndValidateImage(imagePath);
          if (imageData == null || imageData.isEmpty) {
            throw Exception('Failed to load valid image data from $imagePath');
          }
    
          // Step 2: Add image to the map style
          await _addImageToStyle(markerIconName, imageData);
    
          // Step 3: Create symbol options with null checks
          final symbolOptions = SymbolOptions(
            geometry: position,
            iconImage: markerIconName,
            iconSize: iconSize,
            iconRotate: iconRotation,
            // Ensure the icon appears above other map features
            iconAnchor: 'bottom',
            draggable: false,
          );
    
          // Step 4: Add the symbol with error catching
          final symbol = await controller.addSymbol(symbolOptions);
          
          print('[SUCCESS] Marker added successfully with ID: ${symbol.id}');
          return symbol;
        } catch (e, stackTrace) {
          print('[ERROR] Failed to add marker: $e');
          print('[STACK TRACE] $stackTrace');
          rethrow;
        }
      }
    
      /// Load and validate image data
      Future<Uint8List?> _loadAndValidateImage(String imagePath) async {
        try {
          print('[DEBUG] Loading image from: $imagePath');
          final ByteData data = await rootBundle.load(imagePath);
          final Uint8List bytes = data.buffer.asUint8List();
          
          if (bytes.isEmpty) {
            throw Exception('Image data is empty');
          }
          
          print('[DEBUG] Image loaded successfully: ${bytes.length} bytes');
          return bytes;
        } catch (e) {
          print('[ERROR] Failed to load image: $e');
          return null;
        }
      }
    
      /// Add image to map style with validation
      Future<void> _addImageToStyle(String iconName, Uint8List imageData) async {
        try {
          // Check if the image already exists in the style
          await controller.removeImage(iconName).catchError((e) {
            // Ignore errors if the image doesn't exist
            print('[DEBUG] No existing image to remove: $e');
          });
    
          // Add the new image
          await controller.addImage(iconName, imageData);
          print('[DEBUG] Image added to map style: $iconName');
        } catch (e) {
          print('[ERROR] Failed to add image to style: $e');
          throw Exception('Failed to add image to map style: $e');
        }
      }
    }
    
    // Usage example
    class MapScreen extends StatefulWidget {
      @override
      _MapScreenState createState() => _MapScreenState();
    }
    
    class _MapScreenState extends State<MapScreen> {
      MapLibreMapController? _mapController;
      MapMarkerManager? _markerManager;
    
      Future<void> _onMapCreated(MapLibreMapController controller) async {
        setState(() {
          _mapController = controller;
          _markerManager = MapMarkerManager(controller);
        });
    
        // Wait for the map style to load completely
        await Future.delayed(Duration(milliseconds: 500));
    
        try {
          await _markerManager?.addMarkerToMap(
            imagePath: 'images/marker.png',
            position: LatLng(40.7342891, -73.9910334),
            iconSize: 0.5,
          );
        } catch (e) {
          print('[ERROR] Failed to add marker: $e');
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return MapLibreMap(
          onMapCreated: _onMapCreated,
          initialCameraPosition: CameraPosition(
            target: LatLng(40.7342891, -73.9910334),
            zoom: 13.0,
          ),
          styleString: "YOUR_MAPLIBRE_STYLE_URL",
        );
      }
    }
    

    Create an instance of MapMarkerManager in your map screen:

    final markerManager = MapMarkerManager(_mapController);
    

    Call the addMarkerToMap method:

    await markerManager.addMarkerToMap(
      imagePath: 'images/marker.png',
      position: LatLng(40.7342891, -73.9910334),
    );
    

    Here are some additional troubleshooting tips:

    • Make sure your marker image isn’t too large. A size of 32×32 or 64×64 pixels is recommended.

    • Check your pubspec.yaml formatting:

        flutter:
          assets:
            - images/marker.png  # Make sure there's exactly two spaces before the hyphen
    
    • If the marker still doesn’t appear, try adjusting the iconSize parameter – sometimes the default size might be too small or large depending on your image.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search