Google Maps Android API v2 - Interactive InfoWindo

2018-12-31 04:48发布

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:

Example Image

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?

7条回答
爱死公子算了
2楼-- · 2018-12-31 05:03

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;
    }
查看更多
看淡一切
3楼-- · 2018-12-31 05:09

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 :)

查看更多
琉璃瓶的回忆
4楼-- · 2018-12-31 05:09

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.

查看更多
大哥的爱人
5楼-- · 2018-12-31 05:18

I have build a sample android studio project for this question.

output screen shots :-

enter image description here

enter image description here

enter image description here

Download full project source code Click here

Please note: you have to add your API key in Androidmanifest.xml

查看更多
墨雨无痕
6楼-- · 2018-12-31 05:19

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/

查看更多
浪荡孟婆
7楼-- · 2018-12-31 05:21

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.

查看更多
登录 后发表回答