I mean if i click marker OnMarkerClickListener is called, so the OnMapClickListener did not. Even if i set mMap.setOnMarkerClickListener(null); marker object still masks all click events for underlying map and objects.
How can i set Marker transparent for all user interractions?
This is indeed a "limitation" of markers as of 3.1.59 version of the library.
If you really need them to be markers, please post a feature request on gmaps-api-issues for MarkerOptions.clickable and Marker.setClickable.
If you can, consider using other visual objects, e.g. GroundOverlay. The only problem is they all scale with map, unlike markers. The closest would be Circle with zero radius and 20-50 dp stroke width, but that's only a single color dot.
According to the docs about markers, if you add your own Listener and the onMarkerClick() method returns false, the default behaviour will be executed.
So, in the onMarkerClick() just return true and do nothing else to completely overwrite the default.
The only workaround I found for this issue is to execute the same code in OnMarkerClickListener that you have in OnMapClickListener and return false:
getMap().setOnMarkerClickListener(new OnMarkerClickListener() {
public boolean onMarkerClick(Marker marker) {
onMapClick(marker.getPosition());
return true;
}
});
You can skip setting Marker.Title and in this case the marker won't be clickable. Use Marker.Tag if you need to associate some data (like id or name) with the marker without an ability for end-user to tap and see that.
Make your class implementing Google Maps implement OnMarkerClickListener, i.e.:
public class GoogleMapFragment extends Fragment implements MapImplementation, OnMapReadyCallback,
GoogleMap.OnMapClickListener, GoogleMap.OnMarkerClickListener {
and then implement method inside:
#Override
public boolean onMarkerClick(#NonNull Marker marker) {
// Make Marker not clickable in practice
return true;
}
Related
I am using Google Maps in Android with about 800 markers that I want to cluster and 80 markers that I do not want to cluster.
For the markers that I want to cluster, I add to the clusterManager using
mClusterManager.addItem(annotation);
For the markers that I do not want to cluster, I add them directly to the markerCollection
Marker marker = mClusterManager.getMarkerCollection().addMarker(annotation.getMarkerOptions());
Here annoation refers to an instance of AirMapMarker which is a custom class that implements ClusterItem
annotation contains a custom information such as identification string that I need to use when user taps on the marker.
The problem is, I cannot register onClickListener for both the cluster and the mapMarker. If I do, only map's onMarkerClickListener fires.
map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
public boolean onMarkerClick(Marker marker) {
// Handle marker click fires correctly.
}
}
mClusterManager.setOnClusterItemClickListener(new ClusterManager.OnClusterItemClickListener<AirMapMarker>(){
public boolean onClusterItemClick(AirMapMarker marker) {
// Doesn't Fire
}
}
Now the problem is, inside onMarkerClick, I need access to identification which is part of AirMapMarker, in the case if the marker click happened on a single unclustered marker. I could not figure out a way to map Marker to AirMapMarker inside onMarkerClick.
I also tried completely removing map.setOnMarkerClickListener and rely only on mClusterManager.setOnClusterItemClickListener. However, now the problem is that when the marker click happens on markers that are not part of the cluster, onClusterItemClick fires with parameter null. This is because when adding marker to the map, you provide markerOptions and not ClusterItem object.
There is option inside ClusterManager to turn off clustering but this happens globally and not for a particular markers.
Anyone help me out or give me suggestions on what I should try next?
I don't know if I understood your question right. But here is a possible solution.
The markers you want to cluster, you can add them to the ClusterManager.
clusterManager.addItem(yourItem);
The ones you don't want to cluster, you can add them directly to your GoogleMap object.
map.addMarker
Inside your MarkerRenderer you can override
protected void onClusterItemRendered(YourClusterItem clusterItem, Marker marker)
and map yourClusterItem to your Marker if needed. Or you can set a tag to your marker indicating it's a clusterItem.
In public boolean onMarkerClick(Marker marker)
you can check your tag (or your map) to have a different behaviour for each kind of marker.
I made simple application where I get markers based on screen coordinates from the server. Problem is that markers doesn't appear on map immediately. User user must zoom in or zoom out only then marker is visible. Why is that? Is it possible to show marker as soon when marker data is downloaded from server? Or is it possible to somehow refresh map? I know that in previous version there was method map.invalidate() that is basically what I need to have now. Unfortunately this method is not available now.
I will add code snippet how my markers is added
#Override
protected void onPostExecute(ArrayList<MarkerItemData> markerItemData) {
super.onPostExecute(markerItemData);
if(markerItemData != null) {
mClusterManager.addItems(markerItemData);
}
}
It needs re-clustering again.
mClusterManager.addItems(markerItemData);
mClusterManager.cluster();
Because, when you add or remove an ClusterItem (MarkerItemData), it just performs the algorithm and calculates clusters. But does not render on map
Finally, ClusterManager listens onCameraIdle event(includes zoom events) and invokes cluster() method internally. This is the answer of user must zoom in or zoom out only then marker is visible.
From the javadoc here, you need to recluster your markers after adding them to your ClusterManager doing mClusterManager.cluster().
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 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.