Search code examples
google-mapsfluttergoogle-maps-markers

Update custom marker's icons depending on a variable in Flutter


I'm a total noob with flutter and I'm trying to create an app that shows me some markers on a map pointing the location of some sensors. The icons for the markers will be different depending on the data collected for each sensor.

Map with custom markers

So far I have managed to:

  • show the map on users location
  • Place markers for all the sensors
  • Change marker icon to a custom icon
  • Add dialog box, containing sensor's data, for each marker

What I need:

  • Use different icons for markers depending on sensor's data

This is how I display markers on the map:

@override
     Widget build(BuildContext context) {    
       
      var userLocation = Provider.of<UserLocation>(context );
      
      Set<Marker> markers = Set();           
   
   
   //this cycle creates markers with sensor's data
      for(var i=0;   i < sensors.length ; i++){
       var tempF=(strSensors[i]["temp_f"]).toString();
       double pm2_5= double.parse(strSensors[i]["PM2_5Value"]);     
       
       //It returns a tuple wit Aqi value(item1) and description(item2). Depending on item1 value the marker's icon should change.  
       var Aqi=AqiCalculation().AqiValue(pm2_5);


      //my attempt to update the value of the asset's path depending on Aqi.item1 value 
       setState((){
         marcador=updateCustomMapPin(Aqi.item1); 
       });       
       
   
        Marker resultMarker = Marker(
     
        markerId: MarkerId(strSensors[i]["ID"].toString()),     
        position: LatLng(strSensors[i]["Lat"].toDouble(),strSensors[i]["Lon"].toDouble()),
        icon: BitmapDescriptor.fromBytes(markerIcon),
        onTap: (){  

          //shows an image in dialog box depending on Aqi value
                   if(Aqi.item1 > 80){
                     image="https://i.gifer.com/72fB.gif";               
                   }
                   else{
                     image= "https://raw.githubusercontent.com/Shashank02051997/FancyGifDialog-Android/master/GIF's/gif14.gif";
                   }                                    
                  
   
        String tempC;
                   tempC=((int.parse(tempF)-32)/1.8).toStringAsPrecision(4);                   
   
                                showDialog<void>(                                   
                       context: context,
                       builder: (_) => NetworkGiffyDialog(
                               key: keys[1],                            
                               image: Image.network(
                                 image,
                                 fit: BoxFit.cover,                              
                                // alignment:Alignment.bottomLeft,
                               ),
                               entryAnimation: EntryAnimation.TOP_LEFT,
                               title: Text('Sensor: ${strSensors[i]["Label"]}'
                               ,
                                 textAlign: TextAlign.center,
                                 style: TextStyle(
                                     fontSize: 22.0, fontWeight: FontWeight.bold),
                               ),
                               description: Text(
                                 'PM2.5: $pm2_5 Temp:${tempC}° Aqi:${Aqi.item1} Status:${Aqi.item2}',
                                 textAlign: TextAlign.center,
                                 style: TextStyle(
                                     fontSize: 22.0, fontWeight: FontWeight.normal),
                                  
                               ),
                               
                               onlyOkButton: true,
                               onOkButtonPressed: (){
                                 Navigator.pop(context);//closes dialogbox
                               },                                   
                             )
                    );          
             
        }
       );
   // Add it to Set
       markers.add(resultMarker);
       }  

To change the default marker icon I did this:

  @override
     void initState(){
       super.initState();
       setCustomMappin('android/assets/Cloudgray.png');
        }
    
    //Converts image to Unint8List
         Future<Uint8List> getBytesFromAsset(String path, int width) async {
      ByteData data = await rootBundle.load(path);
      ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width);
      ui.FrameInfo fi = await codec.getNextFrame();
      return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List();
    }

   
     
     void setCustomMappin(marker)async {

       markerIcon = await getBytesFromAsset(marker, 150);
     }

This changes all the icons to my default icon's asset. I tried to update the asset's path dynamically by passing this on the loop that creates all the markers:

setState((){
             marcador=updateCustomMapPin(Aqi.item1); 
           }); 

which uses this function:

    //returns icon path depending on the value
     updateCustomMapPin(value)  {
    
      String marker='';
    
           if(value<=50){
            marker = 'android/assets/Cloudgreen.png';
           }
           else if(value>50  && value<=100){
             marker='android/assets/Cloudyellow.png';
           }
           else if(value>100  && value<=150){
             marker='android/assets/CloudOrange.png';
           }
           else if(value>150  && value<=200){
             marker='android/assets/Cloudred.png';
          

 }
       else if(value>200  && value<=300){
         marker='android/assets/Cloudpurple.png';
       }
       else{
       marker='android/assets/Cloudtoxic.png';
       }

       return marker;
      
     }

And this is where I'm stuck, the marker's icon doesn't change despite that, at the moment when every marker is created the proper icon is indicated.

Maybe is a problem of me understanding the life cycle of a Flutter app, I hope you can help me.


Solution

  • I solve this by setting all the custom pins in the initState method, the problem occurred beacause the convertion of the images to bytes is an async process and due to the way I set the dynamic election of the markers it didn't have enough time to make that convertion. So what I did was set a method that converted every image to bytes in the initState, pass those values to global variables and then use them in a conditional for every case.