I have a map in which I am creating different types of markers. I cannot assign an info window adapter to a marker (gee wouldn't that be nice), I can only assign on InfoWindowAdapter for the entire map (at least I think).
My problem is that I want to show a different type of info widow depending on what I clicked. Id the only way to set one InfoWindowAdapter that will handle creating the correct type of info window based on the marker that I am passed?
Am I missing something easy?
When you add a marker to the map, you are receiving back an ID, which uniquely identifies your marker.
You can create an instance of your InfoWindowAdapter immediately after you add the marker and put it in a map, which keeps the ID as key and your InfoWindowAdapter as value.
Marker marker = map.addMarker(options);
// Create your special infoWindowAdapter for this marker
// ...
adapterMap.put(marker.getId(), youSpecialInfoWindowAdapter);
In the one central InfoWindowAdapter, which you register at the map, you can just use the ID of the marker to get the specific InfoWindowAdapter and delegate to the methods of that.
Access to the map can e.g. be provided in the constructor of the InfoWindowAdapter (to avoid global or static variables):
class CentralInfoWindowAdapter implements InfoWindowAdapter {
Map<String, GoogleMap.InfoWindowAdapter> adapterMap;
public CentralInfoWindowAdapter(
Map<String, GoogleMap.InfoWindowAdapter> adapterMap) {
this.adapterMap = adapterMap;
}
#Override
public View getInfoContents(Marker marker) {
InfoWindowAdapter adapter = adapterMap.get(marker.getId());
return adapter.getInfoContents(marker);
}
#Override
public View getInfoWindow(Marker marker) {
InfoWindowAdapter adapter = adapterMap.get(marker.getId());
return adapter.getInfoWindow(marker);
}
}
You can vary this principle of course. If you have only a few different InfoWindowAdapters depending on the "type" of the marker, you may put an enumeration into the map, which identifies the type of your marker and lets you decide, which kind of real InfoWindowAdapter to use inside the central InfoWindowAdapter, or you may still put instances of your special InfoWindowAdapter into the map, but use the same instance for the same type of marker.
if i am right you want to show a different window adapter on each marker?.. if yes you can add a tag on each marker then inside one of the two infowindow function either infowindow() or infocontents() checks the marker tag and add the appropriate layout.
Related
Is there a way of calling onClick event of a specific marker manually (without physically tapping the marker)?
No, but you can simulate the onClick event. 2 things happen when you click a marker:
The info window for the corresponding clicked marker is shown.
The camera pans to the marker.
The above can be achieved with 2 lines of code:
marker.showInfoWindow();
map.animateCamera(CameraUpdateFactory.newLatLng(marker.getPosition()), 250, null);
Try this ,
Implement marker click listener from your map class ,
public class MapView extends FragmentActivity implements OnMarkerClickListener{}
it will override onMarkerClickEvent as follows ,
#Override
public boolean onMarkerClick(final Marker marker) {}
NO, you can't triger a marker click event directly (from code).
You can just use mMap.setOnMarkerClickListener(...);, to handle markers click event.
But there is an alternative if you use your map in WebView, so you can trigger a marker click event with JavaScript:
//In V2 version:
GEvent.trigger(markers[i], 'click');
//In V3 version:
google.maps.event.trigger(markers[i], 'click');
The answer is no. You can't set the onClick of a particular marker separately.
However , using Map.setOnMarkerClickListener(_) you can set a listener for all such events. You should be able to retrieve the marker object in the listener called whenever any marker is clicked . You can use some identification to see if this is the particular marker you desire and act accordingly.
The identification could be any of the properties specific to that marker , title being the obvious choice. However, you can filter markers using any desired property.
I just stumbled across this and wasn't helped by the answers. So for future readers - if you are adding a map.setOnMarkerClickListener(yourClickHandler), then it's quite straight forward.
Abstract the logic from yourClickHandler and keep a reference to all the markers... I.e.
private val markers = arrayListOf<Marker>()
Wherever you add your markers to the map, also add them to your markers array. I.e. something like
val marker = MarkerOptions().position(...).......
markers.add(map.addMarker(marker))
And yourClickHandler would look something like
val yourClickHandler = GoogleMap.OnMarkerClickListener {
markerClickHandler(marker = it)
return#OnMarkerClickListener false
}
Now, whenever you press a marker on the map, yourClickHandler will call markerClickHandler() and whatever you do in there will happen. Also, when you wan't to press a marker programmatically, simply pass that marker to markerClickHandler.
You CAN simulate a marker click. Create your MyMarkerManager class extending from MarkerManager class.
The class has a function onMarkerClick() which you can call manually to simulate the event.
For more details refer this link.
https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/MarkerManager.java
The GoogleMap object has a method Marker addMarker(mk: MarkerOptions) that returns a proper Marker instead of MarkerOptions.
So as soon as you add it you can simulate click behavior as follows:
fun addAndZoom(mk: MarkerOptions, needsHighlight: Boolean) {
mapView.getMapAsync { map ->
val actualMarker = map.addMarker(mk)
if(needsHighlight) {
val cameraUpdate = CameraUpdateFactory.newLatLngZoom(mk.position, 14F)
map.animateCamera(cameraUpdate)
actualMarker.showInfoWindow()
}
}
}
I want to build an interactive Android map app. It will have different marker types and lots of of different options when clicking on them.
First approach :
I started with the notion I will use custom infowindows but figured out that a map can have only single InfoWindowAdapter, with that said, this approach has another fault. InfoWindows can't have click listeners registered to them and I need to have some clickable UI to show after marker click.
Second approach :
Marker click triggers an alertDialog which corresponds to the marker type. I'm hesitant because I'll have lots of switch case inside the OnActivityResult.
Example - dialog fragments with OnActivityResult
Any other ideas ? Am I missing something ?
I ran into similar problem some time ago and I "hacked" it as follows:
mGoogleMap.setInfoWindowAdapter(new InfoWindowAdapter() {
#Override
public View getInfoWindow(Marker pMarker) {
MarkerDescriptor descriptor = mMarkerDescriptorsMap.get(pMarker);
mGoogleMap.setOnInfoWindowClickListener(descriptor.getOnInfoWindowClickListener(MapActivity.this));
return descriptor.getInfoWindowView();
}
}
MarkerDescriptor should be simple interface that will be implemented for each specific marker type:
public interface MarkerDescriptor {
public View getInfoWindowView();
public OnInfoWindowClickListener getOnInfoWindowClickListener(Context pContext);
}
And to keep the references:
private Map<Marker, MarkerDescriptor> mMarkerDescriptorsMap = new HashMap<Marker, MarkerDescriptor>();
Basics of this idea is that GoogleMap can have only one marker selected at the time, so when user chooses another marker, we change the listeners.
I have a weird problem which didn't seem to be an issue until recently. I have a map fragment which adds markers to a map, and associates them with a java Map collection of '<'marker id's, object they are associated with'>' for the getInfoWindow call.
This works fine, 9 items are added to the map with ids m0-m8. However when I leave the fragment and re-enter it, the markers are added to the map with unique numbers again, so second time around the ids are m9-m17 etc.
The problem is that the marker's onInfoClick retains the old ids.
CustomInfoWindowAdapter() {
mWindow = getActivity().getLayoutInflater().inflate(R.layout.custom_info_window, null);
}
#Override
public View getInfoWindow(final Marker marker) {
//Here marker.getId() is usually always a value between m0-m8
Business markerBusiness = mMarkersMap.get(marker.getId());
//Render and do other things
return mWindow();
}
How can I either force the addMarker() call to forget the id's from before OR make sure the new markers match the onInfoClick final marker ids? To further complicate things it seems this problem occurs only certain markers which I can't understand at all!
Let me know if more code is needed, I'm not sure what is necessary, I set a new infoWindowAdapter every-time the map fragment is recreated:
mMap.setInfoWindowAdapter(new CustomInfoWindowAdapter());
//Add markers to the map
mMarkersMap.put(newMarker.getId(), business);
I have to start some activity with clicking on infoWindow (I can do this with setOnInfoWindowClickListener()), but this activity can be different, and I need something else. I should have a possibility to set an ID to every map marker. Can I pass custom ID to every Marker on map? Or how I can create button in infoWindow with this id (if I can do this, I can pass this id).
I suggest using a HashMap or something similar. As you iterate over your list of objects and create markers for them, also add the Marker to a list, using the ID of the object as the key, and the marker as the value:
private HashMap<Integer, Marker> markerMap = new HashMap<Integer, Marker>();
...
for(MarkerObject obj : this.markerObjects)
{
//If the marker isn't already being displayed
if(!markerMap.containsKey(obj.getId()))
{
//Add the Marker to the Map and keep track of it
this.markerMap.put(obj.getId(), this.mMap.addMarker(getMarkerForObject(obj)));
}
}
Then you can use a OnInfoWindowClickListener to find the object id of the tapped marker in your Map and do something with the corresponding data, like open a new activity with details.
I've got an Activity that holds a ListFragment on the left and a SupportMapFragment on the right.
List and Map are both backed by the same data. The visual representation of the data on the Map are Markers.
I want to be able to perform a click on either a list item or a Marker and get the corresponding item in the other visual representation.
Restrictions of the framework and my data are:
The Marker class is final and the Marker's id does not have a modificator. This is why I can't use the easiest possible way.
"It's important to not hold on to objects (e.g. Marker) beyond the
view's life. Otherwise it will cause a memory leak as the view cannot
be released." (see SupportMapFragment)
Titles of Markers can occur multiple times. This is why the expensive String comparison is not a way I can go.
Does anyone have a working solution for this issue or can provide a nudge in the right direction?
If you want to be able to register to clicks on a Marker, you'll need to override the InfoWindowAdapter.
You can provide unique information to the title and snippet of a Marker and implement the interface's methods in this style:
#Override
public View getInfoWindow(Marker marker) {
// do nothing here in order to obtain the original info window border.
return null;
}
#Override
public View getInfoContents(Marker marker) {
// Create your own view here. Obtain the unique information stored
// in title / snippet of the current marker.
return createdView;
}
Now you can set the OnInfoWindowClickListener and work with the unique information stored there.
Here's another option. The latest APIs provide an OnMarkerClickListener interface.
https://developers.google.com/maps/documentation/android/marker#marker_click_events