Google Maps Android API v2 - Interactive InfoWindow (like in original android google maps)
Solution 1
I was looking for a solution to this problem myself with no luck, so I had to roll my own which I would like to share here with you. (Please excuse my bad English) (It's a little crazy to answer another Czech guy in English :-) )
The first thing I tried was to use a good old PopupWindow
. It's quite easy - one only has to listen to the OnMarkerClickListener
and then show a custom PopupWindow
above the marker. Some other guys here on StackOverflow suggested this solution and it actually looks quite good at first glance. But the problem with this solution shows up when you start to move the map around. You have to move the PopupWindow
somehow yourself which is possible (by listening to some onTouch events) but IMHO you can't make it look good enough, especially on some slow devices. If you do it the simple way it "jumps" around from one spot to another. You could also use some animations to polish those jumps but this way the PopupWindow
will always be "a step behind" where it should be on the map which I just don't like.
At this point, I was thinking about some other solution. I realized that I actually don't really need that much freedom - to show my custom views with all the possibilities that come with it (like animated progress bars etc.). I think there is a good reason why even the google engineers don't do it this way in the Google Maps app. All I need is a button or two on the InfoWindow that will show a pressed state and trigger some actions when clicked. So I came up with another solution which splits up into two parts:
First part:
The first part is to be able to catch the clicks on the buttons to trigger some action. My idea is as follows:
- Keep a reference to the custom infoWindow created in the InfoWindowAdapter.
- Wrap the
MapFragment
(orMapView
) inside a custom ViewGroup (mine is called MapWrapperLayout) - Override the
MapWrapperLayout
's dispatchTouchEvent and (if the InfoWindow is currently shown) first route the MotionEvents to the previously created InfoWindow. If it doesn't consume the MotionEvents (like because you didn't click on any clickable area inside InfoWindow etc.) then (and only then) let the events go down to the MapWrapperLayout's superclass so it will eventually be delivered to the map.
Here is the MapWrapperLayout's source code:
package com.circlegate.tt.cg.an.lib.map;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.Marker;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
public class MapWrapperLayout extends RelativeLayout {
/**
* Reference to a GoogleMap object
*/
private GoogleMap map;
/**
* Vertical offset in pixels between the bottom edge of our InfoWindow
* and the marker position (by default it's bottom edge too).
* It's a good idea to use custom markers and also the InfoWindow frame,
* because we probably can't rely on the sizes of the default marker and frame.
*/
private int bottomOffsetPixels;
/**
* A currently selected marker
*/
private Marker marker;
/**
* Our custom view which is returned from either the InfoWindowAdapter.getInfoContents
* or InfoWindowAdapter.getInfoWindow
*/
private View infoWindow;
public MapWrapperLayout(Context context) {
super(context);
}
public MapWrapperLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MapWrapperLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Must be called before we can route the touch events
*/
public void init(GoogleMap map, int bottomOffsetPixels) {
this.map = map;
this.bottomOffsetPixels = bottomOffsetPixels;
}
/**
* Best to be called from either the InfoWindowAdapter.getInfoContents
* or InfoWindowAdapter.getInfoWindow.
*/
public void setMarkerWithInfoWindow(Marker marker, View infoWindow) {
this.marker = marker;
this.infoWindow = infoWindow;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean ret = false;
// Make sure that the infoWindow is shown and we have all the needed references
if (marker != null && marker.isInfoWindowShown() && map != null && infoWindow != null) {
// Get a marker position on the screen
Point point = map.getProjection().toScreenLocation(marker.getPosition());
// Make a copy of the MotionEvent and adjust it's location
// so it is relative to the infoWindow left top corner
MotionEvent copyEv = MotionEvent.obtain(ev);
copyEv.offsetLocation(
-point.x + (infoWindow.getWidth() / 2),
-point.y + infoWindow.getHeight() + bottomOffsetPixels);
// Dispatch the adjusted MotionEvent to the infoWindow
ret = infoWindow.dispatchTouchEvent(copyEv);
}
// If the infoWindow consumed the touch event, then just return true.
// Otherwise pass this event to the super class and return it's result
return ret || super.dispatchTouchEvent(ev);
}
}
All this will make the views inside the InfoView "live" again - the OnClickListeners will start triggering etc.
Second part: The remaining problem is, that obviously, you can't see any UI changes of your InfoWindow on screen. To do that you have to manually call Marker.showInfoWindow. Now, if you perform some permanent change in your InfoWindow (like changing the label of your button to something else), this is good enough.
But showing a button pressed state or something of that nature is more complicated. The first problem is, that (at least) I wasn't able to make the InfoWindow show normal button's pressed state. Even if I pressed the button for a long time, it just remained unpressed on the screen. I believe this is something that is handled by the map framework itself which probably makes sure not to show any transient state in the info windows. But I could be wrong, I didn't try to find this out.
What I did is another nasty hack - I attached an OnTouchListener
to the button and manually switched it's background when the button was pressed or released to two custom drawables - one with a button in a normal state and the other one in a pressed state. This is not very nice, but it works :). Now I was able to see the button switching between normal to pressed states on the screen.
There is still one last glitch - if you click the button too fast, it doesn't show the pressed state - it just remains in its normal state (although the click itself is fired so the button "works"). At least this is how it shows up on my Galaxy Nexus. So the last thing I did is that I delayed the button in it's pressed state a little. This is also quite ugly and I'm not sure how would it work on some older, slow devices but I suspect that even the map framework itself does something like this. You can try it yourself - when you click the whole InfoWindow, it remains in a pressed state a little longer, then normal buttons do (again - at least on my phone). And this is actually how it works even on the original Google Maps app.
Anyway, I wrote myself a custom class which handles the buttons state changes and all the other things I mentioned, so here is the code:
package com.circlegate.tt.cg.an.lib.map;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import com.google.android.gms.maps.model.Marker;
public abstract class OnInfoWindowElemTouchListener implements OnTouchListener {
private final View view;
private final Drawable bgDrawableNormal;
private final Drawable bgDrawablePressed;
private final Handler handler = new Handler();
private Marker marker;
private boolean pressed = false;
public OnInfoWindowElemTouchListener(View view, Drawable bgDrawableNormal, Drawable bgDrawablePressed) {
this.view = view;
this.bgDrawableNormal = bgDrawableNormal;
this.bgDrawablePressed = bgDrawablePressed;
}
public void setMarker(Marker marker) {
this.marker = marker;
}
@Override
public boolean onTouch(View vv, MotionEvent event) {
if (0 <= event.getX() && event.getX() <= view.getWidth() &&
0 <= event.getY() && event.getY() <= view.getHeight())
{
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: startPress(); break;
// We need to delay releasing of the view a little so it shows the pressed state on the screen
case MotionEvent.ACTION_UP: handler.postDelayed(confirmClickRunnable, 150); break;
case MotionEvent.ACTION_CANCEL: endPress(); break;
default: break;
}
}
else {
// If the touch goes outside of the view's area
// (like when moving finger out of the pressed button)
// just release the press
endPress();
}
return false;
}
private void startPress() {
if (!pressed) {
pressed = true;
handler.removeCallbacks(confirmClickRunnable);
view.setBackground(bgDrawablePressed);
if (marker != null)
marker.showInfoWindow();
}
}
private boolean endPress() {
if (pressed) {
this.pressed = false;
handler.removeCallbacks(confirmClickRunnable);
view.setBackground(bgDrawableNormal);
if (marker != null)
marker.showInfoWindow();
return true;
}
else
return false;
}
private final Runnable confirmClickRunnable = new Runnable() {
public void run() {
if (endPress()) {
onClickConfirmed(view, marker);
}
}
};
/**
* This is called after a successful click
*/
protected abstract void onClickConfirmed(View v, Marker marker);
}
Here is a custom InfoWindow layout file that I used:
<?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:gravity="center_vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginRight="10dp" >
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:text="Title" />
<TextView
android:id="@+id/snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="snippet" />
</LinearLayout>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
Test activity layout file (MapFragment
being inside the MapWrapperLayout
):
<com.circlegate.tt.cg.an.lib.map.MapWrapperLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/map_relative_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<fragment
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.google.android.gms.maps.MapFragment" />
</com.circlegate.tt.cg.an.lib.map.MapWrapperLayout>
And finally source code of a test activity, which glues all this together:
package com.circlegate.testapp;
import com.circlegate.tt.cg.an.lib.map.MapWrapperLayout;
import com.circlegate.tt.cg.an.lib.map.OnInfoWindowElemTouchListener;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private ViewGroup infoWindow;
private TextView infoTitle;
private TextView infoSnippet;
private Button infoButton;
private OnInfoWindowElemTouchListener infoButtonListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final MapFragment mapFragment = (MapFragment)getFragmentManager().findFragmentById(R.id.map);
final MapWrapperLayout mapWrapperLayout = (MapWrapperLayout)findViewById(R.id.map_relative_layout);
final GoogleMap map = mapFragment.getMap();
// MapWrapperLayout initialization
// 39 - default marker height
// 20 - offset between the default InfoWindow bottom edge and it's content bottom edge
mapWrapperLayout.init(map, getPixelsFromDp(this, 39 + 20));
// We want to reuse the info window for all the markers,
// so let's create only one class member instance
this.infoWindow = (ViewGroup)getLayoutInflater().inflate(R.layout.info_window, null);
this.infoTitle = (TextView)infoWindow.findViewById(R.id.title);
this.infoSnippet = (TextView)infoWindow.findViewById(R.id.snippet);
this.infoButton = (Button)infoWindow.findViewById(R.id.button);
// Setting custom OnTouchListener which deals with the pressed state
// so it shows up
this.infoButtonListener = new OnInfoWindowElemTouchListener(infoButton,
getResources().getDrawable(R.drawable.btn_default_normal_holo_light),
getResources().getDrawable(R.drawable.btn_default_pressed_holo_light))
{
@Override
protected void onClickConfirmed(View v, Marker marker) {
// Here we can perform some action triggered after clicking the button
Toast.makeText(MainActivity.this, marker.getTitle() + "'s button clicked!", Toast.LENGTH_SHORT).show();
}
};
this.infoButton.setOnTouchListener(infoButtonListener);
map.setInfoWindowAdapter(new InfoWindowAdapter() {
@Override
public View getInfoWindow(Marker marker) {
return null;
}
@Override
public View getInfoContents(Marker marker) {
// Setting up the infoWindow with current's marker info
infoTitle.setText(marker.getTitle());
infoSnippet.setText(marker.getSnippet());
infoButtonListener.setMarker(marker);
// We must call this to set the current marker and infoWindow references
// to the MapWrapperLayout
mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow);
return infoWindow;
}
});
// Let's add a couple of markers
map.addMarker(new MarkerOptions()
.title("Prague")
.snippet("Czech Republic")
.position(new LatLng(50.08, 14.43)));
map.addMarker(new MarkerOptions()
.title("Paris")
.snippet("France")
.position(new LatLng(48.86,2.33)));
map.addMarker(new MarkerOptions()
.title("London")
.snippet("United Kingdom")
.position(new LatLng(51.51,-0.1)));
}
public static int getPixelsFromDp(Context context, float dp) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int)(dp * scale + 0.5f);
}
}
That's it. So far I only tested this on my Galaxy Nexus (4.2.1) and Nexus 7 (also 4.2.1), I will try it on some Gingerbread phone when I have a chance. A limitation I found so far is that you can't drag the map from where is your button on the screen and move the map around. It could probably be overcome somehow but for now, I can live with that.
I know this is an ugly hack but I just didn't find anything better and I need this design pattern so badly that this would really be a reason to go back to the map v1 framework (which btw. I would really really like to avoid for a new app with fragments etc.). I just don't understand why Google doesn't offer developers some official way to have a button on InfoWindows. It's such a common design pattern, moreover this pattern is used even in the official Google Maps app :). I understand the reasons why they can't just make your views "live" in the InfoWindows - this would probably kill performance when moving and scrolling map around. But there should be some way how to achieve this effect without using views.
Solution 2
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 :)
Solution 3
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/
Solution 4
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;
}
Related videos on Youtube
user1943012
Updated on January 18, 2020Comments
-
user1943012 over 4 years
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 entireInfoWindow
is slected and not just theImageButton
. I read that it is because there isn't aView
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?
-
CommonsWare over 11 years"its not working" is not an especially useful description of your symptoms. Here is a sample project that shows having a custom info window with an image: github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
-
user1943012 over 11 years@CommonsWare I wrote reason of that. From original documentation Note: The info window that is drawn is not a live view. The view is rendered as an image (using
View.draw(Canvas)
)... This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below. ... in your example is only textview -
tkblackbelt about 11 yearsHi, how did you get the my location button to appear below the action bar when in full screen mode? Thanks!
-
Driss Bounouar almost 11 years@tkblackbelt try
relativeLayout
's -
marienke over 9 yearsI don't think that this question should be closed. It's a legit question to a problem I'm also facing.
-
John over 9 yearsI can see this so often, many of the most useful questions with answer have been closed. A question might not always fit the exact requirements of a proper question but if we have a well explained PROBLEM and a well explained ANSWER then there is no reason to close the question. People use Stackoverflow to exchange knowledge and closing a question thread which is so actively and so productive as "off-topic" does not seem like a good idea to me..
-
-
Rarw about 11 yearsDo you override getInfoContents and getInfoWindow where you create the markers? For example, if I am adding different kinds of markers and using different methods, would I just override within the body of each of those methods where I create the different markers?
-
Zeeshan Mirza about 11 yearsYes I override getInfoContents and getInfoWindow.
-
Rarw about 11 yearsJust tried this out and it works jus like inflating any other xml layout - good job
-
user1943012 about 11 yearsIt looks like you didnt read my question. I know how to create custom view inside infowindow. Which i dont know is how to make custom button inside and listen to its click events.
-
Patrick Jackson about 11 yearsinteresting solution. I want to try this. How was the performance?
-
biddulph.r about 11 yearsThis solution does not answer the original question
-
Venkat about 11 yearsactually i place a button on the popup dialog.i write onClickListener for that button.but it is not working. how to write listener for the button in the popup dialog???? @zeeshan0026
-
Harsh Trivedi about 11 yearsHello I have checked your code and it works fine for me but i have one more que that Can we change the position of infowindow from Upper side to right side of marker ???
-
Harsh Trivedi about 11 yearszeeshan i just want to know is it possible or not ?
-
TlmaK0 almost 11 yearsThis solution does not answer the question
-
user2251725 almost 11 yearsi have a issue, toast show after first click button & rortate device.
-
LostPuppy almost 11 yearsyou only receive callbacks for clicks on the info window.
-
Zeeshan Mirza almost 11 years@TlmaK0 We know this is not answer and I also mention it at the end of the answer.
-
user2251725 almost 11 yearschange return type of onTouch(View v,Motion event) of OnInfoWindowElemTouchListener abstract class to true.Then Toast show after click, means touch identify on touch.
-
Balaji almost 11 yearsneed to replace
view.setBackground(bgDrawablePressed);
withif (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }
to work in Android Gingerbread , Note: there is one more occurrence ofview.setBackground
in code. -
HaMMeReD almost 11 yearsThis isn't really the solution, it's just restating the question. This adapter takes a snapshot of the view by rendering it to a bitmap, it's not interactive.
-
rgrocha almost 11 yearsA new optimization for the OnInfoWindowElemTouchListener class: Use view.setPressed() to avoid handling two backgrounds drawables. In this way you can customize the backgrounds using drawable state selectors or any other standard way of assigning backgrounds, just like in a normal layout.
-
Chintan Raghwani almost 11 years@Balaji, I needed to add your code snippet as you suggested that make my code working in newer devices. Thank You, too.
-
Balaji almost 11 years@ChintanRaghwani the original code in the answer will work in newer devices (say jelly bean) , the code snippet in my comment is to make it work for all android build versions.
-
KK_07k11A0585 almost 11 yearsHi @chose007! Thank you very much for your answer but i have a small issue. I was able to show a custom view on marker click but still the default white layout is visible. How to hide that ..
-
chose007 almost 11 yearsKK_07k11A0585: It seems that your InfoWindowAdapter implementation is probably wrong. There are two methods to override: getInfoWindow() and getInfoContents(). The framework first calls the getInfoWindow() method and (only) if it returns null, it calls the getInfoContents(). If you return some View from getInfoWindow, the framework will lay it inside the default info window frame - which in your case you don't want to. So just return null from getInfoWindow and return you View from getInfoContent and it should be fine then.
-
chose007 almost 11 yearsIf anybody is interested, I'm using this solution in my own app - CG Transit (you can find it on Google Play). After two months it has been used by several tens of thousands of users and nobody complained about it yet.
-
Sebastian over 10 yearsI tried your code and yet it worked fine, until I tried opening a dialog from one of the buttons I added. Didn't work. It's saying "BadTokenException: Unable to add window - token null is not for an application". You got any clue on this? EDIT: Fixed it. I used "getApplicationContext()" instead of "this" when building the AlertDialog. Using "this" fixes it.
-
Dory over 10 years@KK_07k11A0585 hey i m also facing same prob like yours. did you solved it.. and how ?
-
Dory over 10 years@chose007 thnks,grt answer !!! Can we have as many buttons on info window and how it handles the click event of one, can all button click event be handled same way.
-
corsair992 over 10 yearsThe
MapView
doesn't clear the transient state of the info window. The reason click listeners don't work properly is that the press release event (and also the press event inside scrolling containers) is posted on theViewRoot
run queue instead of aHandler
if theView
is not attached to aWindow
, and thus will only execute when theViewRoot
is refreshed. My implementation bypasses this issue by creating an invisible wrapper for the info window and adding it to theMapView
wrapper. See the next comment for more. -
corsair992 over 10 years... The wrapper intercepts invalidate and layout request calls from the info window and dispatches them to the
MapView
by callingshowInfoWindow()
on theMarker
(with a refresh buffer to ensure that the state is shown). This should make the info window fully live, although the refresh rate will be much lower than usual. Also, it's easy to enable scrolling on the map while pressing a button by dispatching the touch event to theMapView
also, but then the whole window will be displayed as selected by theMapView
. -
Sergii over 10 yearsThanks for this awesome solution! Is it possible here to make asynchronous update of such InfoWindow, already displayed to the user? The case is about loading images from network EDIT: solution here stackoverflow.com/questions/15503266/…
-
maza23 about 10 yearsis it possible to use getInfoWindow() instead of getInfoContents()?
-
Gaurav Pansheriya about 10 yearsi try this code but i has nullpointerException arise.. at com.ngshah.goglemapv2withlazyloading.MainActivity.onCreate(MainActivity.java:69) arise error exception in this code map.setInfoWindowAdapter(new InfoWindowAdapter() { }
-
edi233 about 10 yearsI loose my gestures after click on marker. Everything is ok, untill I click on marker. After that I can't do zoom by fingers. It seems to me that some view gets my gestures. Any idea?
-
TouchBoarder about 10 yearsdid anyone else got the pressed state to work? I implemented the code as above but used a state drawable, and view.pressed(). And do I need to set the marker and showInfoView() on start/end pressed for this to work?
-
Lee Yi Hong about 10 yearsI tried but there is no feedback after clicking on it. Debug and realise that startPress() is being called but endPress() is not... Anyone face the same problem?
-
Lee Yi Hong about 10 yearsI sorry for spamming... But I found out the reason why mine didn't manage trigger endPress(). I made a mistake with the click element. Instead of Button, I use ImageView. After changing the ImageView to Button. It works perfectly :) Thanks @chose007
-
Frank about 10 yearsI tryed this code, but like @GauravPansheriya i have a null pointer exceptiom in the main activity. mapWrapperLayout is ever null final MapWrapperLayout mapWrapperLayout = (MapWrapperLayout)findViewById(R.id.map_relative_layout);
-
Gorgeous_DroidVirus almost 10 years@chose007 i m trying to create the custom adapter of infowindow and get that but when i try to get the button click on it thats time i am not get the button click.. i think this listener not work in custom adapter of infowindow.. any help..??
-
Herry almost 10 years@chose007 I have use your solution for making button click work for infowindow but when change getInfoContents to use getInfoWindow for create my Map overlay it is now work perfect for deliver click event of Button ,while view return from getInfoContents work well.Do you known how to make it work perfect like it work for getInfoContents.i have to use getInfoWindow because i want to change Frame of Overlay as well.
-
Herry almost 10 years@chose007 i think in your app CG Transityou are using getInfoContents to create view for your Overlay infowindow,Right?but if you change it to getInfoWindowthen it willl effect Click event of Button let me known same happen with you .
-
Pranav Mahajan almost 10 yearsThe solution looks huge but is as simple as Ctrl+C..Ctrl+V
-
Deinlandel over 9 yearsThanks for the answer! Anyone posted it on github? =)
-
Code Word over 9 yearsHi ! I am using the same approach to get a live infowindow with buttons. Though I cannot animate the progress bar inside but it's fine. The problem comes when I navigate back from the map fragment and come back to it. I found the infowindow started behaving like the default one. Now it is no more live. Do you have any solution for this ?
-
Rarw over 9 yearshow do you determine the bottom offset if you're not using a standard infowindow?
-
Manikandan over 9 yearsI add my custom layout. It shows the white rectangle in the background of my custom layout. How to remove the white rectangle.
-
Manikandan over 9 yearsI have a close button in the infowindow, when I click the button, I need to close the infowindow. I just set the visibility of the infowindow to gone. But, when I again click any of the markers, the infowindow doesn't appear. How to fix it?
-
Manikandan over 9 yearsI like to do something on snippet text click. But it is not triggered. How to achieve this?
-
sham.y over 9 yearsHi @manikandan.. instead of touch listner implement onclick listener..Me also working on same.. it is working but sometimes it is not working..I am wondering why it is not working..
-
sham.y over 9 yearshi @chose007 please help me,, i am facing problem with clicking on textview instead of button.. i have 3 textviews with 3 different listners. I changed touch listener with clicklistener.. working fine with one marker.. but for other markers the listners are not calling..please help me..
-
Rethinavel over 9 years@chose007 Will this solution work for Map work for clustering.
-
patrickjason91 about 9 yearsI tried using this hack, it worked at first, but for my use case, I need multiple buttons to be clicked in the InfoWindow. The first button fires the onClickConfirmed callback, however the second button doesnt. Any modifications needed to make multiple buttons work?
-
Johan Karlsson about 9 yearsIt does not seems to really answer the original question. Maybe you could expand the answer to be a full answer? Otherwise it seems no idea to upvote this answer.
-
Johan Karlsson about 9 yearsI don´t think it is interesting to post a speculation as an answer. Maybe it should be a comment on the original question. Just my thoughts.
-
harikrishnan about 9 yearsHi, i tried like, write on click listener for more than one button means, listener is not working.. only, single button listener is working fine.. can you reply is it possible to write on click for more than one buttton
-
Barodapride about 9 yearsHow do you deal with different resolutions needing a different bottomOffsetPixels? You cannot hard code bottomOffsetPixels
-
Jaffar Raza about 9 yearsIf we load a map fragment inside the fragment than whether this should be supported or not.
-
Volodymyr Kulyk about 9 yearsChange OnInfoWindowElemTouchListener onTouch to return true; and this work for me.
-
Shehan Ekanayake about 9 yearsThis will slow down/lag scrolling the map
-
Manish Jangid about 8 yearscan you show me your code ? I was able to log touch events successfully but not click events so I went for this implementation. Also, you need to implement choose007's solution properly.
-
Manish Jangid about 8 yearsI shared my complete implementation. Let me know if you have any queries
-
Marc Plano-Lesay over 7 yearsFor a weird reason,
View.OnClickListener
doesn't work on Android 7. Using aView.OnTouchListener
filtered onMotionEvent.ACTION_UP
works fine as a work-around. -
Carson over 7 yearsThis is amazing, not only is it the perfect solution for my map, but it also taught me a lot about how to make custom views.
-
Deyan Genovski over 7 yearsThis library github.com/Appolica/InteractiveInfoWindowAndroid does something similar
-
Mithun Sarker Shuvro over 7 years@chose007 great solution, but I am facing a small issue, how can I make infowindow transparent? I can make it transparent but returning getInfoWindow a non null value, but then click event doesn't work
-
Noundla Sandeep over 7 yearsIt's better to share your code through Github/gist instead of zip file. So we can directly check there.
-
Morozov about 7 yearsa little bug i found, when u press on some button, all buttons are clicked.
-
Fullhdpixel about 7 yearsDo you know how to change this implementation for a gridview? I outlined my question here: stackoverflow.com/questions/43655642/…
-
Ganesh Mohan almost 7 years@Noundla & others: do not bother downloading his zipped code. It's an exact copy paste of the accepted answer for this question.
-
Onkar Nene almost 7 years@ganesh2shiv is right, the zipped code is useless. You shouldn't be attached copy pasted code
-
Yog Guru almost 7 yearsCan any buddy help.. This is not working for me. I followed all the steps mentioned in the answer but no luck. Checked in OS 7 in device MOTO G4+.
-
gcolucci over 6 yearsIs it possible to use it with clusters?
-
Yogendra Patel over 3 yearsis this library work with react native expo project?
-
Jasmin Sojitra about 2 yearsCan you suggest how to make Edit text work in this? I have added Edit text but I am unable to click on it. prnt.sc/NcF6ZwDo6STJ