2

Im having trouble using a custom marker in my GoogleMaps project with flutter. I get this error when the map screen loads

Exception has occurred. LateError (LateInitializationError: Field 'myMarker' has not been initialized.)

I tried without using late and it says myMarker has to be initialized so I declared it as late and then initialized it in the initState. That didn't work so I tried with a nullable ? and that did not work either. Any help would be appreciated. Thanks

import 'dart:async';
import 'dart:developer';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:location/location.dart';
import 'dart:math' as math;

import './main.dart' as main;
import './variables.dart' as variables;
import './methods.dart' as methods;
import './mapvariables.dart' as mapVar;
import './marker_information.dart' as markerInfo;

class MapScreen extends StatefulWidget {
  const MapScreen({Key? key}) : super(key: key);

  @override
  _MapScreenState createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  Completer<GoogleMapController> _controllerGoogleMap = Completer();
  late GoogleMapController newGoogleMapController;
  Position? currentPosition;
  var geoLocator = Geolocator();
  final double dcheck = 0.00014128694207108202;
  var location = new Location();
  late BitmapDescriptor myMarker;

  @override
  void initState() {
    super.initState();
    setMarker();
  }

  void setMarker() async {
    myMarker = await BitmapDescriptor.fromAssetImage(
        ImageConfiguration(), 'loginlogo.png');
  }

  checkpermission_location() async {
    var locationStatus = await Permission.location.status;
    print(locationStatus);

    if (!locationStatus.isGranted) {
      print("gr");
      print(await Permission.location.value);
      await Permission.location.request();
      checkpermission_location();
    }

    if (!locationStatus.isDenied) {
      print('de');
      await Permission.location.request();
      checkLocation();
    }
  }

  void checkClue(var x, var y, markerInfo.ClueLocation marker) {
    double distance = methods.distance(marker.lat, marker.long, x, y);
    log("distance: $distance");
    if ((distance < dcheck)) {
      variables.dialogVis = true;
      if ((variables.dialogVis) && (marker.compl == false)) {
        mapVar.showAlertDialog(context, marker);
        variables.dialogVis = false;
        marker.compl = true;
      }
    }
  }

  void checkLocation() {
    location.onLocationChanged.listen((LocationData currentLocation) {
      var lat = currentLocation.latitude;
      var long = currentLocation.longitude;
      checkClue(lat, long, markerInfo.newHamCollege);
      checkClue(lat, long, markerInfo.coeFen);
      checkClue(lat, long, markerInfo.mathematicalBridge);
      checkClue(lat, long, markerInfo.graveYard);
      checkClue(lat, long, markerInfo.archeologicalMuseum);
      checkClue(lat, long, markerInfo.addenbrokesHospital);
      checkClue(lat, long, markerInfo.stMarysBellTower);
      checkClue(lat, long, markerInfo.trinityStreet);
      checkClue(lat, long, markerInfo.viewOfTheBridgeOfSighs);
    });
  }

  //Initial camera position when maps first load
  static const _initalCameraPosition = CameraPosition(
    target: LatLng(52.2053, 0.1218),
    zoom: 11.5,
  );

  Marker makeMarker(markerInfo.ClueLocation marker) {
    return (Marker(
        markerId: MarkerId(marker.title),
        infoWindow: InfoWindow(title: marker.title),
        icon: myMarker,
        position: LatLng(marker.lat, marker.long),
        onTap: () {
          if (marker.compl) {
            mapVar.showAlertDialog(context, marker);
          }
        }));
  }

  //Google map widget
  @override
  Widget build(BuildContext context) {
    //Checks if mapAcess is true
    if (variables.mapAccess) {
      var currentlocation = location.getLocation();
      return Scaffold(
        body: GoogleMap(
          onMapCreated: (GoogleMapController controller) {
            controller.setMapStyle(mapVar.mapStyle);
            checkpermission_location();
            _controllerGoogleMap.complete(controller);
            newGoogleMapController = controller;
          },
          mapType: MapType.normal,
          myLocationButtonEnabled: true,
          zoomControlsEnabled: true,
          myLocationEnabled: true,
          zoomGesturesEnabled: true,
          markers: {
            //Markers located in the variables.dart file
            makeMarker(markerInfo.newHamCollege),
            makeMarker(markerInfo.coeFen),
            makeMarker(markerInfo.mathematicalBridge),
            makeMarker(markerInfo.graveYard),
            makeMarker(markerInfo.archeologicalMuseum),
            //6.??? Waiting for update from Konstantin
            makeMarker(markerInfo.addenbrokesHospital),
            makeMarker(markerInfo.stMarysBellTower),
            makeMarker(markerInfo.trinityStreet),
            makeMarker(markerInfo.viewOfTheBridgeOfSighs),
          },
          initialCameraPosition: _initalCameraPosition,
        ),
      );
    }
    //Refuses access if 10 Digit key is not provided
    return Scaffold(
        body: Center(
            child: Text('You do not have access to the map, please login')));
  }
}

6
  • everything looks okay except for the asset path. Make sure to pass the full relative path eg. assets/images/loginlogo.png depending on your folder structure Commented Mar 22, 2022 at 19:46
  • @MarcosMaliki I still have the same issue, changed it to assets/loginlogo.png Commented Mar 22, 2022 at 19:50
  • Have you declared you asset in you pubspec.yaml Commented Mar 22, 2022 at 19:52
  • @MarcosMaliki Yes it looks like this assets: - assets/ Commented Mar 22, 2022 at 19:53
  • share a screenshot of your folder structure Commented Mar 22, 2022 at 19:55

1 Answer 1

3

You pretty much have it the same way I do it; the way I've done it is as follows:

  1. Set up the BitmapDescriptor as a nullable property at the top of your state class, as well as I create a markers Set:
Set<Marker>? _markers = <Marker>{};
BitmapDescriptor? myMarker

I create an async method that I run at the beginning of the build method (I do it in the build method because I need the build context sometimes), that asynchronously loads the bitmaps, as in:

void setMarkerIcon() async {
  myMarker = await BitmapDescriptor.fromAssetImage(
        const ImageConfiguration(size: Size(50, 50)),'loginlogo.png');
}

Then in the build method I just call it:

@override
  Widget build(BuildContext context) {
    
    // you can call it here
    setMarkerIcons();

    return Scaffold(
      body: GoogleMap(
        markers: _markers!,
        onMapCreated: (GoogleMapController ctrl) {
          
          // here after map is loaded, I generate the markers
          generateMarkers();
        }
      )
    );

BONUS:

Then as shown above, upon the map getting created, I can go ahead and use the custom markers, based on a list of locations, as such:

void generateMarkers() {
    var localMarkers = <Marker>{};

    for(var location in locationsList!) {
      localMarkers.add(
        Marker(
          markerId: MarkerId(location.id!),
          position: LatLng(location.lat!, location.lng!),
          icon: myMarker
        )
      );
    }

    if (mounted) {
        setState(() {
          _markers = localMarkers;
        });
      }
  } 
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you this works, would you also know how to update this to a different image once the user has done something within the app. Basically change the logo from one color to another.
Yes, you would basically add another BitmapDescriptorImage that represents the changed icon, and you saw the markers set I created - well, you can find the marker to be changed by ID within that set, replace it with a new Marker object, adding the different marker by setting its icon properly. Unfortunately the Marker’s icon property is a one-time assignment, you cannot edit it, that’s why you have to create a new updated marker. Then do all this within the setState so it rebuilds the markers.
@RomanJaquez could you please check this and confirm what am I doing wrong here? gist.github.com/rajesh-h/916cfc21e31fa3d0625595a70df95088 I get the """The argument type 'BitmapDescriptor?' can't be assigned to the parameter type 'BitmapDescriptor'"""

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.