Google Maps Android API v2-Интерактивное InfoWindow (как в оригинальных Android Google maps)


Я пытаюсь сделать пользовательский InfoWindow после нажатия на маркер с новым Google Maps API v2. Я хочу, чтобы это выглядело как в оригинальном приложении maps от Google. Вот так:

когда я ImageButton внутри, его не работает-весь InfoWindow вырезается и не только ImageButton. Я читал, что это потому, что нет View сам по себе, но это снимок, поэтому отдельные элементы нельзя отличить друг от друга.

EDIT: В документация (благодаря Disco S2):

как уже упоминалось в предыдущем разделе на окнах, окна не живой вид, а вид изображения на карта. В результате все прослушиватели, установленные в представлении, игнорируются и вы не можете различать события щелчка на различных частях вид. Вам не рекомендуется размещать интерактивные компоненты-такие как кнопки, флажки, поля ввода - в вашей пользовательской информации окно.

но если Google использует его, должен быть какой-то способ сделать это. У кого-нибудь есть идеи?

7 178

7 ответов:

я сам искал решение этой проблемы без удачи, поэтому мне пришлось свернуть свой собственный, который я хотел бы поделиться здесь с вами. (Пожалуйста, извините мой плохой английский) (это немного сумасшедший, чтобы ответить другой чешский парень на английском языке :-) )

первое, что я попытался было использовать старый добрый PopupWindow. Это довольно легко - нужно только слушать OnMarkerClickListener а затем показать пользовательский PopupWindow выше маркера. Некоторые другие ребята здесь, на StackOverflow, предложили это решение, и оно на самом деле выглядит довольно хорошо на первый взгляд. Но проблема с этим решением появляется, когда вы начинаете перемещать карту. Вы должны переместить PopupWindow как-то самостоятельно, что возможно (слушая некоторые события onTouch), но IMHO вы не можете заставить его выглядеть достаточно хорошо, особенно на некоторых медленных устройствах. Если вы делаете это простым способом, он "прыгает" с одного места на другое. Вы также можете использовать некоторые анимации, чтобы отполировать эти прыжки, но таким образом PopupWindow всегда будет "на шаг позади", где это должно быть на карте, которая мне просто не нравится.

в этот момент я думал о каком-то другом решении. Я понял, что мне на самом деле не нужно так много свободы - чтобы показать свои пользовательские взгляды со всеми возможностями, которые приходят с ним (например, анимированные индикаторы прогресса и т. д.). Я думаю, что есть веская причина, почему даже инженеры google не делают это таким образом в приложении Google Maps. Все, что мне нужно, это кнопка или две на InfoWindow, которая покажет нажатое состояние и вызовет некоторые действия при нажатии. Поэтому я придумал еще одно решение, которое делится на две части:

первая часть:
Первая часть должна быть в состоянии поймать щелчки по кнопкам, чтобы вызвать некоторые действия. Моя идея заключается в следующем:

  1. Сохраните ссылку на пользовательское infoWindow, созданное в InfoWindowAdapter.
  2. оберните MapFragment (или MapView) внутри пользовательской группы просмотра (моя называется MapWrapperLayout)
  3. переопределить MapWrapperLayout's dispatchTouchEvent и (если InfoWindow в настоящее время отображается) первый маршрут MotionEvents к ранее созданному InfoWindow. Если он не потребляет MotionEvents (например, потому, что вы не нажимали на любую кликабельную область внутри InfoWindow и т. д.) затем (и только тогда) пусть события спускаются в суперкласс MapWrapperLayout, чтобы он в конечном итоге был доставлен на карту.

вот MapWrapperLayout по исходный код:

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);
    }
}

все это снова сделает просмотры внутри InfoView "живыми" - OnClickListeners начнут запускать и т. д.

вторая часть: Остальная проблема заключается в том, что, очевидно, вы не можете видеть никаких изменений пользовательского интерфейса вашего InfoWindow на экране. Для этого вам нужно вручную вызвать маркер.showInfoWindow. Теперь, если вы выполняете некоторые постоянные изменения в своем InfoWindow (например, меняете метку своей кнопки на что-то другое), это хорошо достаточно.

но показывать состояние нажатия кнопки или что-то в этом роде сложнее. Первая проблема заключается в том, что (по крайней мере) я не смог заставить InfoWindow показывать обычное состояние нажатия кнопки. Даже если я нажимал кнопку в течение длительного времени, она просто оставалась не нажатой на экране. Я считаю, что это то, что обрабатывается самой структурой карты, которая, вероятно, не показывает никакого переходного состояния в информационных окнах. Но я мог ошибаться, я не пытался чтобы выяснить это.

то, что я сделал, это еще один неприятный Хак - я прикрепил OnTouchListener к кнопке и вручную переключил ее фон, когда кнопка была нажата или отпущена на два пользовательских чертежа - один с кнопкой в нормальном состоянии, а другой в нажатом состоянии. Это не очень приятно, но работает :). Теперь я мог видеть, как кнопка переключается между нормальным и нажатым состояниями на экране.

есть еще один последний глюк - при нажатии кнопки слишком быстро, он не показывает нажатое состояние - он просто остается в своем нормальном состоянии (хотя сам щелчок срабатывает, поэтому кнопка "работает"). По крайней мере, так это выглядит на моем Galaxy Nexus. Поэтому последнее, что я сделал, это то, что я немного задержал кнопку в нажатом состоянии. Это также довольно уродливо, и я не уверен, как это будет работать на некоторых старых, медленных устройствах, но я подозреваю, что даже сама структура карты делает что-то вроде этого. Вы можете попробовать это сами - когда вы нажимаете на весь InfoWindow, он остается в нажатом состоянии немного дольше, чем обычные кнопки (снова - по крайней мере, на моем телефоне). И это на самом деле, как это работает даже на оригинальном приложении Google Maps.

в любом случае, я написал себе пользовательский класс, который обрабатывает изменения состояния кнопок и все другие вещи, которые я упомянул, так что вот код:

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);
}

вот пользовательский файл макета InfoWindow, который я использовал:

<?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>

файл макета тестовой активности (MapFragment будучи внутри 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>

и, наконец, исходный код тестового действия, который склеивает все это вместе:

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);
    }
}

вот и все. До сих пор я тестировал это только на своем Galaxy Nexus (4.2.1) и Nexus 7 (также 4.2.1), я попробую его на каком-нибудь пряничном телефоне, когда у меня будет шанс. Ограничение, которое я нашел до сих пор, заключается в том, что вы не можете перетащить карту с того места, где находится ваша кнопка на экране, и переместить карту. Вероятно, это можно было бы как-то преодолеть, но сейчас я могу жить с этим что.

я знаю, что это уродливый хак, но я просто не нашел ничего лучше, и мне так нужен этот шаблон дизайна, что это действительно будет повод вернуться к структуре map v1 (которая кстати. Я бы действительно очень хотел, чтобы избежать нового приложения с фрагментами и т. д.). Я просто не понимаю, почему Google не предлагает разработчикам какой-то официальный способ иметь кнопку на InfoWindows. Это такой общий шаблон дизайна, причем этот шаблон используется даже в официальном приложении Google Maps :). Я понимаю причины, по которым они не могут просто сделать ваши взгляды "живыми" в InfoWindows - это, вероятно, убьет производительность при перемещении и прокрутке карты. Но должен быть какой-то способ, как достичь этого эффекта без использования представлений.

Я вижу, что этот вопрос уже старый, но все же...

мы сделали библиотеку sipmle в нашей компании для достижения желаемого-интерактивное информационное окно с видами и все такое. Вы можете проверить это на github.

надеюсь, это поможет:)

вот мой взгляд на проблему. Я создаю AbsoluteLayout наложение, которое содержит информационное окно (обычный вид с каждым битом интерактивности и возможностей рисования). Тогда я начинаю Handler которая синхронизирует позицию информационного окна с позиции точку на карте каждые 16 мс. Звучит глупо, но действительно работает.

демонстрационное видео:https://www.youtube.com/watch?v=bT9RpH4p9mU (учтите, что производительность снижается из-за эмулятора и записи видео работает одновременно).

код демо:https://github.com/deville/info-window-demo

статья с подробностями (на русском языке):http://habrahabr.ru/post/213415/

для тех, кто не мог получить choose007's ответ и работает

если clickListener не работает должным образом во все времена в chose007's решение, попробуйте реализовать View.onTouchListener вместо clickListener. Обрабатывать событие касания с помощью любого действия ACTION_UP или ACTION_DOWN. Почему-то карты infoWindow вызывает странное поведение при отправке в 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: вот как я сделал это шаг за шагом

первый надуть свой собственный infowindow (глобальная переменная) где-то в вашей деятельности/фрагмент. Мой находится внутри фрагмента. Также убедитесь, что корневой вид в вашем макете infowindow является linearlayout (по какой-то причине relativelayout принимал полную ширину экрана в 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;

затем в onmapready обратный вызов google maps android api (следуйте этому, если вы не знаете, что такое onMapReady Карты > Документация - Начало)

   @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 инициализация http://stackoverflow.com/questions/14123243/google-maps-android-api-v2- интерактивное-infowindow-like-in-original-android-go / 15040761#15040761 39-высота маркера по умолчанию 20-смещение между нижним краем InfoWindow по умолчанию и нижним краем содержимого * /

        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

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;
            }
        });

ручка маркер нажмите отдельно

    @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;
    }

просто предположение, у меня недостаточно опыта, чтобы попробовать его... ) -:

поскольку GoogleMap является фрагментом, должно быть возможно поймать событие маркера onClick и показать custom фрагмент вид. Фрагмент карты будет по-прежнему виден на заднем плане. Кто-нибудь пробовал? Любая причина, почему это не сработает?

недостатком является то, что фрагмент карты будет заморожен на backgroud, пока пользовательский фрагмент информации не вернет ему управление.

Я построил пример проекта android studio для этого вопроса.

выход скриншоты :-

enter image description here

enter image description here

enter image description here

скачать полный исходный код проекта выберитездесь

обратите внимание: вы должны добавить свой ключ API в Androidmanifest.xml

Это действительно просто.

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;

            }

        });

просто добавьте выше код в свой класс, где вы используете GoogleMap. Макет р..info_window_layout наш пользовательский макет, который показывает мнение о том, что придет на место infowindow. Я только что добавил textview здесь. Вы можете добавить дополнительный вид здесь, чтобы сделать его похожим на образец оснастки. Мой info_window_layout был

<?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>

Я надеюсь, что это поможет. Мы можем найти рабочий пример пользовательского infowindow по адресу http://wptrafficanalyzer.in/blog/customizing-infowindow-contents-in-google-map-android-api-v2-using-infowindowadapter/#comment-39731

редактировать : этот код показывает, как мы можем добавить пользовательский вид на infoWindow. Этот код не обрабатывает клики по элементам пользовательского представления. Так что это близко к ответу, но не совсем ответ, поэтому он не принимается в качестве ответа.