I am trying to a make custom InfoWindow
after a click on a marker with the new Google Maps API v2. I want it to look like in the original maps application by Google. Like this:
When I have ImageButton
inside, its not working - the entire InfoWindow
is slected and not just the ImageButton
. I read that it is because there isn't a View
itself but it's snapshot, so individual items cannot be distinguished from each other.
EDIT: In the documentation (thanks to Disco S2):
As mentioned in the previous section on info windows, an info window is not a live View, rather the view is rendered as an image onto the map. As a result, any listeners you set on the view are disregarded and you cannot distinguish between click events on various parts of the view. You are advised not to place interactive components — such as buttons, checkboxes, or text inputs — within your custom info window.
But if Google use it, there must be some way to make it. Does anyone have any idea?
This question is related to
android
google-maps
infowindow
google-maps-android-api-2
Here's my take on the problem. I create AbsoluteLayout
overlay which contains Info Window (a regular view with every bit of interactivity and drawing capabilities). Then I start Handler
which synchronizes the info window's position with position of point on the map every 16 ms. Sounds crazy, but actually works.
Demo video: https://www.youtube.com/watch?v=bT9RpH4p9mU (take into account that performance is decreased because of emulator and video recording running simultaneously).
Code of the demo: https://github.com/deville/info-window-demo
An article providing details (in Russian): http://habrahabr.ru/post/213415/
I have build a sample android studio project for this question.
output screen shots :-
Download full project source code Click here
Please note: you have to add your API key in Androidmanifest.xml
For those who couldn't get choose007's
answer up and running
If clickListener
is not working properly at all times in chose007's
solution, try to implement View.onTouchListener
instead of clickListener
. Handle touch event using any of the action ACTION_UP
or ACTION_DOWN
. For some reason, maps infoWindow
causes some weird behaviour when dispatching to clickListeners
.
infoWindow.findViewById(R.id.my_view).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (action){
case MotionEvent.ACTION_UP:
Log.d(TAG,"a view in info window clicked" );
break;
}
return true;
}
Edit : This is how I did it step by step
First inflate your own infowindow (global variable) somewhere in your activity/fragment. Mine is within fragment. Also insure that root view in your infowindow layout is linearlayout (for some reason relativelayout was taking full width of screen in infowindow)
infoWindow = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.info_window, null);
/* Other global variables used in below code*/
private HashMap<Marker,YourData> mMarkerYourDataHashMap = new HashMap<>();
private GoogleMap mMap;
private MapWrapperLayout mapWrapperLayout;
Then in onMapReady callback of google maps android api (follow this if you donot know what onMapReady is Maps > Documentation - Getting Started )
@Override
public void onMapReady(GoogleMap googleMap) {
/*mMap is global GoogleMap variable in activity/fragment*/
mMap = googleMap;
/*Some function to set map UI settings*/
setYourMapSettings();
MapWrapperLayout
initialization
http://stackoverflow.com/questions/14123243/google-maps-android-api-v2-
interactive-infowindow-like-in-original-android-go/15040761#15040761
39 - default marker height
20 - offset between the default InfoWindow bottom edge and it's content bottom edge
*/
mapWrapperLayout.init(mMap, Utils.getPixelsFromDp(mContext, 39 + 20));
/*handle marker clicks separately - not necessary*/
mMap.setOnMarkerClickListener(this);
mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
YourData data = mMarkerYourDataHashMap.get(marker);
setInfoWindow(marker,data);
mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow);
return infoWindow;
}
});
}
SetInfoWindow method
private void setInfoWindow (final Marker marker, YourData data)
throws NullPointerException{
if (data.getVehicleNumber()!=null) {
((TextView) infoWindow.findViewById(R.id.VehicelNo))
.setText(data.getDeviceId().toString());
}
if (data.getSpeed()!=null) {
((TextView) infoWindow.findViewById(R.id.txtSpeed))
.setText(data.getSpeed());
}
//handle dispatched touch event for view click
infoWindow.findViewById(R.id.any_view).setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = MotionEventCompat.getActionMasked(event);
switch (action) {
case MotionEvent.ACTION_UP:
Log.d(TAG,"any_view clicked" );
break;
}
return true;
}
});
Handle marker click separately
@Override
public boolean onMarkerClick(Marker marker) {
Log.d(TAG,"on Marker Click called");
marker.showInfoWindow();
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(marker.getPosition()) // Sets the center of the map to Mountain View
.zoom(10)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition),1000,null);
return true;
}
It is really simple.
googleMap.setInfoWindowAdapter(new InfoWindowAdapter() {
// Use default InfoWindow frame
@Override
public View getInfoWindow(Marker marker) {
return null;
}
// Defines the contents of the InfoWindow
@Override
public View getInfoContents(Marker marker) {
// Getting view from the layout file info_window_layout
View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);
// Getting reference to the TextView to set title
TextView note = (TextView) v.findViewById(R.id.note);
note.setText(marker.getTitle() );
// Returning the view containing InfoWindow contents
return v;
}
});
Just add above code in your class where you are using GoogleMap. R.layout.info_window_layout is our custom layout that is showing the view that will come in place of infowindow. I just added the textview here. You can add additonal view here to make it like the sample snap. My info_window_layout was
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="@+id/note"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
I hope it will help. We can find a working example of custom infowindow at http://wptrafficanalyzer.in/blog/customizing-infowindow-contents-in-google-map-android-api-v2-using-infowindowadapter/#comment-39731
EDITED : This code is shows how we can add custom view on infoWindow. This code did not handle the clicks on Custom View items. So it is close to answer but not exactly the answer that's why It is not accepted as answer.
Just a speculation, I have not enough experience to try it... )-:
Since GoogleMap is a fragment, it should be possible to catch marker onClick event and show custom fragment view. A map fragment will be still visible on the background. Does anybody tried it? Any reason why it could not work?
The disadvantage is that map fragment would be freezed on backgroud, until a custom info fragment return control to it.
I see that this question is already old but still...
We made a sipmle library at our company for achieving what is desired - An interactive info window with views and everything. You can check it out on github.
I hope it helps :)
Source: Stackoverflow.com