How to determine which marker was pressed on the map - google-maps

I am unable to determine which marker was tapped by the user on Google maps. I've added onTap: _onMarkerTapped(MarkerId markerId) event where I try to open another page with a more detailed Google Map based on which marker user has tapped. When I add bunch of markers (as a Set of markers) to my Google map, I do use unique markerId and that's what I pass in as an argument to a private custom method _onMarkerTapped(). The issue is, inside thsi event I always ended up getting the last markerId i.e. the last marker which I added to the Set. Is there any way to get the current markerid which user has tapped?
add onTap event handler for every marker I added in a set of Markers
for (var campusData in Campuses.campusLocations) {
campusDetails = json.decode(campusData);
campus = Campus.fromJson(campusDetails);
markerId = MarkerId(i.toString());
mrkr = new Marker(
markerId: markerId, // a string for marker unique id
icon: BitmapDescriptor.fromAsset(
'assets/wsu#2x.png'), // options for hues and custom imgs
position:
LatLng(campus.latitude, campus.longitude), // lat and long doubles
onTap: () {
_onMarkerTapped(markerId);
});
campusMarkers.add(mrkr);
i++;
}
return GoogleMap(
initialCameraPosition: cameraPosition,
onMapCreated: _onMapCreated,
mapType: MapType.normal,
markers: campusMarkers,
onTap: (lng) => _onMapTapped(lng),
);
void _onMarkerTapped(MarkerId markerId) {
final Marker tappedMarker = campusMarkers.elementAt(int.parse(markerId.value));
if (tappedMarker != null) {
}
else{
print("Tapped marker is NULL..");
}
}
Looking for ways to determine which marker was tapped by the user

Pay attention to these two line:
markerId = MarkerId(i.toString());
...
onTap: () {
_onMarkerTapped(markerId);
}
You are not creating a uniqueMarkerId for each loop, you are just reassigning it, so the last one you assigned will always be used by _onMarkerTapped(markerId). To fix this, use:
final markerId = MarkerId(i.toString());

For anyone who come across this issue, please follow the code example at https://github.com/flutter/plugins/blob/master/packages/google_maps_flutter/example/lib/place_marker.dart .. especially the _add() method and _onMarkerTapped() methods. PLEASE make sure to use a Map to declare your set of markers e.g. Map<MarkerId, Marker> markers = <MarkerId, Marker>{};

Related

Flutter - Provide Real-Time Updates to Google Maps Using StreamBuilder

I'm currently building an application that displays markers on a Google Map. The location of the markers is being pulled from a Firestore database. Currently, I am successfully retrieving and displaying all markers. However, I need to update the icon of each marker based on their boolean value in the database.
Here is how I am currently displaying the markers.
I create the map in the main build:
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: mapToggle
? GoogleMap(
onMapCreated: onMapCreated,
compassEnabled: false,
polylines: route,
initialCameraPosition: CameraPosition(
target: LatLng(currentLocation.latitude,
currentLocation.longitude),
zoom: 12),
markers: markers,
)
: Center(
child: Text('Loading... Please wait...',
style: TextStyle(fontSize: 20.0)),
)),
Then I call this function in the initState to grab my markers:
chargePoints() {
_database.collection('charge_points').getDocuments().then((docs) {
if (docs.documents.isNotEmpty) {
for (int i = 0; i < docs.documents.length; i++) {
initMarker(docs.documents[i].data, docs.documents[i].documentID);
}
}
});
Finally, the initMarker function adds each marker to the Set marker, taken by the Google Map instance:
void initMarker(chargePoint, documentID) {
var markerIdVal = documentID;
final MarkerId markerId = MarkerId(markerIdVal);
// Creating a new Charge Point Marker
final Marker marker = Marker(
markerId: markerId,
icon: markerIcon,
position: LatLng(chargePoint['location'].latitude,
chargePoint['location'].longitude),
infoWindow: InfoWindow(
title: chargePoint['name'], snippet: chargePoint['type']),
onTap: () {
findBookings(context, chargePoint, documentID);
});
setState(() {
markers.add(marker);
});
So my question is; how can I return this data as a Stream, and provide a listener that updates the respective marker icon, when the "occupied" field has been changed?
Firestore
Map UI
Okay, I got a solution!
I'm now returning a StreamBuilder in the main build Widget that takes a Firestore query to return the details of all markers.
I then use the snapshot provided by the stream to intermittently transform the state of all markers set in the initMarker function above.
Additionally, the markers Set is now a Map. This makes more sense for accessing the markers to perform updates.
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
The markers are managed using their MarkerId, which correlates to the documentID of all results returned in the snapshot.
I don't believe this solution is perfect, but I hope I've helped someone out!
StreamBuilder<QuerySnapshot>(
stream: _servicesObj.getChargePoints(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Text('Loading Points');
}
snapshot.data.documents.forEach((change) {
var markerIdVal = change.documentID;
final MarkerId markerId = MarkerId(markerIdVal);
if (change.data['occupied'] == true) {
markers[markerId] = Marker(
markerId: markerId,
icon: pointOccupiedIcon,
position: LatLng(change.data['location'].latitude,
change.data['location'].longitude),
infoWindow: InfoWindow(
title: change.data['name'],
snippet: change.data['type']),
onTap: () {
findBookings(context, change.data, change.documentID);
});
} else {
markers[markerId] = Marker(
markerId: markerId,
icon: pointAvailableIcon,
position: LatLng(change.data['location'].latitude,
change.data['location'].longitude),
infoWindow: InfoWindow(
title: change.data['name'],
snippet: change.data['type']),
onTap: () {
findBookings(context, change.data, change.documentID);
});
}
});

Flutter google maps: update markers

I'm trying to update the coordinates of a marker (Google Maps flutter)
I'm 'creating' the marker like this.
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
Uint8List resizedMarkerImageBytesTemp = await convertUserImage(
"imgurl");
MarkerId id = MarkerId(uid);
Marker _marker = Marker(
markerId: id,
onTap: () {
print("tapped");
},
position: LatLng(lat, lng),
icon: BitmapDescriptor.fromBytes(resizedMarkerImageBytesTemp),
infoWindow: InfoWindow(title: 'myTitle'),
);
setState(() {
markers[id] = _marker;
});
What's the best / most efficient way to update the coordinates of a marker?
Thanks!
UPDATE: I tried the following.
MarkerId id = MarkerId(uid); //uid of the marker I want to update
markers[id].position.longitude = 3.12493;
But then I get the error:
error: 'longitude' can't be used as a setter because it is final.
You can create a function and pass the markerId to replace the actual marker:
updateMarker(id){
final marker = markers.values.toList().firstWhere((item) => item.markerId == id);
Marker _marker = Marker(
markerId: marker.markerId,
onTap: () {
print("tapped");
},
position: LatLng(marker.position.latitude, marker.position.longitude),
icon: marker.icon,
infoWindow: InfoWindow(title: 'my new Title'),
);
setState(() {
//the marker is identified by the markerId and not with the index of the list
markers[id] = _marker;
});
}
You can easily use this code anywhere you want to change the position:
setState((){markers[id]=markers[id].copyWith(positionParam:LatLng(yournewlat,your new long));});
You can even use it in marker on tap callback.

Adding markers dynamically to flutter google map

I'm using Flutter to make a mobile application that uses a map. We decided to use Google map and the plugin for flutter we use is:
google_maps_flutter: ^0.5.7
I understand that adding markers to the map works like this:
Map<MarkerId, Marker> markers = <MarkerId, Marker>{};
Marker _marker = new Marker(
icon: BitmapDescriptor.defaultMarker,
markerId: _markerId,
position: LatLng(34.024441,-5.0310968),
infoWindow: InfoWindow(title: "userMarker", snippet: '*'),
);
GoogleMap _map;
#override
void initState(
markers[_markerId] = _marker;
_map = new GoogleMap(
/* other properties irrelevant to this prob */
markers: Set<Marker>.of(_markers.values),
);
);
The above snippet does work, I get to see the marker on the map. But modifying the marker or trying to add another marker like in the snippet below does not work.
FloatingActionButton(
onPressed: () {
setState(() {
_marker = new Marker(
icon: BitmapDescriptor.defaultMarker,
markerId: _markerId,
position: LatLng(currentLocation.latitude, currentLocation.longitude),
infoWindow: InfoWindow(title: "userMarker", snippet: '*'),
onTap: () {
debugPrint("Marker Tapped");
},
);
markers[_markerId] = _marker; // What I do here is modify the only marker in the Map.
});
markers.forEach((id,marker) { // This is used to see if the marker properties did change, and they did.
debugPrint("MarkerId: $id");
debugPrint("Marker: [${marker.position.latitude},${marker.position.longitude}]");
});
});
)
My intention here is using another plugin (geoLocator) to get location data of the user and change the only marker I have so it can track his movements. The debugPrint shows that the data is indeed changing, but I see no change in the map (the initial marker that I change uses a different location than my own when I test).
If there's no specific reason for you to use Map data structure, here's what I've done in the past.
I have a Set of Marker in my State
Set<Marker> markers = Set();
Give it to the map widget. markers: markers
GoogleMap(
onMapCreated: _onMapCreated,
myLocationEnabled: true,
initialCameraPosition:
CameraPosition(target: LatLng(0.0, 0.0)),
markers: markers,
)
And then adding the Marker, which I'm building with search result and which you'll be building with your user's location, to Set of Marker in setState method.
// Create a new marker
Marker resultMarker = Marker(
markerId: MarkerId(responseResult.name),
infoWindow: InfoWindow(
title: "${responseResult.name}",
snippet: "${responseResult.types?.first}"),
position: LatLng(responseResult.geometry.location.lat,
responseResult.geometry.location.lng),
);
// Add it to Set
markers.add(resultMarker);
Edit: I've just noticed you're using GoogleMap widget in your initState, you need to move it to the build method if you want to rebuild it everytime with the new state values.

How to customize myLocationEnabled button on Google Maps?

I need to create a button which is going to show me the current location of the user. That's why I use Google Maps, which have the options such this one. But, I need to customize the MyLocation Button but don't know how to do it. Could you please help me with this?
I am pretty new in Flutter though :D
I couldn't find easy way of doing it, but since everything is widget in flutter, you can put your google maps in your stack, and add iconbutton or whatever custom button you need to your stack.
GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition:
CameraPosition(target: LatLng(0.0, 0.0)),
markers: markers,
),
IconButton(
icon: Icon(Icons.battery_charging_full),
onPressed: () async {
final center = await getUserLocation();
getNearbyPlaces(center);
Marker myPosition = Marker(
markerId: MarkerId('myLocation'),
position: center == null
? LatLng(0, 0)
: LatLng(center.latitude, center.longitude),
icon: BitmapDescriptor.fromAsset(
'assets/logo.png'));
setState(() {
markers.add(myPosition);
});
},
),
],
)
So what I'm doing here is basicly,
I have Stack which helps me put a IconButton over GoogleMap. When user presssed on that button, I add a new Marker to show current position, There is a Set of Markers on my State, called markers, I'm creating a new Marker by getting the current location of the user, and adding a custom icon to that marker, and then add it to my markers(Set), to display it on GoogleMap.
my getUserLocation function:
Future<LatLng> getUserLocation() async {
LocationManager.LocationData currentLocation;
final location = LocationManager.Location();
try {
currentLocation = await location.getLocation();
final lat = currentLocation.latitude;
final lng = currentLocation.longitude;
final center = LatLng(lat, lng);
return center;
} on Exception {
currentLocation = null;
return null;
}
}
I have location: ^2.1.0 package and using it as LocationManager import 'package:location/location.dart' as LocationManager;

how to clear previous google map markers so only one is on the map at a time

I am trying to make this map only allow one marker on the page at any time but when I click a new marker is placed along with old ones.
Does anyone know how you would make this happen?
google.maps.event.addListener(map, 'click', function(event) {
//set up variables
var clickLat = event.latLng.lat();
var clickLng = event.latLng.lng();
//show lat and long
var loc = document.getElementById("location");
var info = "Latitude: "+clickLat+" "+", longitude: "+clickLng;
loc.innerHTML = info;
//place marker
var marker = new google.maps.Marker({
position: new google.maps.LatLng(clickLat, clickLng),
map: map,
animation: google.maps.Animation.DROP
});
});
I believe your answer is in the Google Mapa API. You just have to set the map of your old marker to null.
Read this: http://code.google.com/apis/maps/documentation/javascript/overlays.html#RemovingOverlays
Another option would be to have a single marker variable and update the position of the marker when someone clicks on the map.
declare a Marker field:
private Marker marker;
then, for the setOnMapClickListener method of your GoogleMap object, do the following:
#Override
public void onMapClick(LatLng point) {
if(marker!=null) marker.remove();
markerSelectedPlace = new MarkerOptions().position(point).title(
"dfsdfsdfs dfsdfsdf");
marker = mMap.addMarker(markerSelectedPlace);
mMap.addMarker(markerSelectedPlace);
marker.showInfoWindow();
}