Google Maps Android API v2 - интерактивное информационное окно (как в оригинальных картах Google для Android)


191

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

Пример изображения

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

РЕДАКТИРОВАТЬ: В документации (спасибо Disco S2 ):

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

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


«не работает» не является особенно полезным описанием ваших симптомов. Вот пример проекта, который показывает наличие пользовательского информационного окна с изображением: github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
CommonsWare

8
@CommonsWare Я написал причину этого. Из оригинальной документации. Примечание. Отображаемое информационное окно не является интерактивным. Представление отображается как изображение (с использованием View.draw(Canvas)) ... Это означает, что любые последующие изменения представления не будут отражены в информационном окне на карте. Чтобы обновить информационное окно позже Кроме того, информационное окно не будет учитывать какую-либо интерактивность, типичную для обычного вида, такую ​​как события касания или жеста. Однако вы можете прослушать общее событие щелчка во всем информационном окне, как описано в разделе ниже. ... в твоем примере только textview
user1943012

Привет, как вы получили кнопку «Мое местоположение» под панелью действий в полноэкранном режиме? Спасибо!
tkblackbelt

45
Я не думаю, что этот вопрос должен быть закрыт. Это законный вопрос к проблеме, с которой я тоже сталкиваюсь.
Мариенке

12
Я вижу это так часто, многие из самых полезных вопросов с ответом были закрыты. Вопрос может не всегда соответствовать точным требованиям правильного вопроса, но если у нас есть хорошо объясненная ПРОБЛЕМА и хорошо объясненный ОТВЕТ, то нет смысла закрывать вопрос. Люди используют Stackoverflow для обмена знаниями и закрытия цепочки вопросов, которая настолько активна и продуктивна, как «не по теме», не кажется мне хорошей идеей ..
Джон

Ответы:


333

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

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

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

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

  1. Сохраните ссылку на пользовательское информационное окно, созданное в InfoWindowAdapter.
  2. Оберните MapFragment(или MapView) внутри пользовательской ViewGroup (моя называется MapWrapperLayout)
  3. Переопределите MapWrapperLayoutdispatchTouchEvent и (если 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 на экране. Для этого вам нужно вручную вызвать Marker.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), я попробую это на каком-нибудь Gingerbread телефоне, когда у меня будет такая возможность. До сих пор я обнаружил ограничение, заключающееся в том, что вы не можете перетаскивать карту из-под своей кнопки на экране и перемещать карту. Возможно, это можно как-то преодолеть, но сейчас я могу жить с этим.

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


6
интересное решение. Я хочу попробовать это. Как прошло представление?
Патрик

10
нужно заменить view.setBackground(bgDrawablePressed);на if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }для работы в Android Gingerbread, обратите внимание: есть еще одно вхождение view.setBackgroundв коде.
Баладжи

4
KK_07k11A0585: Похоже, что ваша реализация InfoWindowAdapter, вероятно, неверна. Есть два метода для переопределения: getInfoWindow () и getInfoContents (). Фреймворк сначала вызывает метод getInfoWindow () и (только), если он возвращает null, вызывает getInfoContents (). Если вы вернете какой-то View из getInfoWindow, фреймворк поместит его в рамку информационного окна по умолчанию - что в вашем случае не нужно Так что просто верните null из getInfoWindow и верните View из getInfoContent, и тогда все будет хорошо.
выбрал007

18
Если кому-то интересно, я использую это решение в своем собственном приложении - CG Transit (вы можете найти его в Google Play). Через два месяца его использовали несколько десятков тысяч пользователей, и никто еще не жаловался на это.
выбрал007

2
Как вы определяете смещение дна, если вы не используете стандартное информационное окно?
Rarw

12

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

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

Я надеюсь, что это помогает :)


Можно ли использовать его с кластерами?
gcolucci

9

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

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

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

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


Это замедлит / задержит прокрутку карты
Шейн Эканаяке

2

Для тех, кто не смог получить 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;
          }

Редактировать: это, как я сделал это шаг за шагом

Сначала надуйте свое собственное информационное окно (глобальную переменную) где-нибудь в вашей деятельности / фрагменте. Моя в пределах фрагмента. Также убедитесь, что корневое представление в макете вашего информационного окна является линейным (по какой-то причине относительное расположение занимало всю ширину экрана в информационном окне)

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 Android (следуйте этому, если вы не знаете, что такое 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- interactive-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;
    }

можешь показать мне свой код? Я смог успешно регистрировать события касания, но не события щелчка, поэтому я пошел на эту реализацию. Кроме того, вам необходимо правильно реализовать решение Choose007.
Маниш Джангид

Я поделился своей полной реализацией. Дайте мне знать, если у вас есть какие-либо вопросы
Маниш Джангид

0

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

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

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


5
Я не думаю, что будет интересно опубликовать предположение в качестве ответа. Возможно, это должен быть комментарий к исходному вопросу. Просто мои мысли.
Йохан Карлссон

1
Эта библиотека github.com/Appolica/InteractiveInfoWindowAndroid делает что-то похожее
Deyan Genovski

-2

Для этого вопроса я создал пример проекта студии android.

вывод снимков экрана: -

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

Скачать полный исходный код проекта Нажмите здесь

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


5
Лучше поделиться своим кодом через Github / gist вместо zip-файла. Так что мы можем прямо проверить там.
Нундла Сандип

небольшая ошибка, которую я обнаружил, когда вы нажимаете на какую-то кнопку, все кнопки нажимаются.
Морозов

3
@Noundla и другие: не беспокойтесь о загрузке его почтового индекса. Это точная копия принятого ответа на этот вопрос.
Ганеш Мохан,

1
@ ganesh2shiv прав, заархивированный код бесполезен. Вам не следует прикреплять скопированный код
Онкар Нене

-7

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

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. R.layout.info_window_layout - это наш пользовательский макет, который показывает вид, который появится вместо информационного окна. Я только добавил текстовое представление здесь. Вы можете добавить дополнительный вид здесь, чтобы сделать его как образец оснастки. Мой 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>

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

РЕДАКТИРОВАНИЕ: Этот код показывает, как мы можем добавить пользовательский вид в infoWindow. Этот код не обрабатывал нажатия на элементы пользовательского просмотра. Поэтому он близок к ответу, но не совсем к ответу, поэтому не принимается как ответ.


Вы переопределяете getInfoContents и getInfoWindow, где вы создаете маркеры? Например, если я добавляю разные виды маркеров и использую разные методы, я бы просто переопределил в теле каждого из этих методов, где я создаю разные маркеры?
Rarw

Да, я переопределяю getInfoContents и getInfoWindow.
Зеешан Мирза

Просто попробовал это, и это работает как раздувание любого другого макета XML - хорошая работа
Rarw

31
Похоже, вы не читали мой вопрос. Я знаю, как создать собственный вид внутри информационного окна. То, что я не знаю, как сделать пользовательскую кнопку внутри и слушать события ее нажатия.
user1943012

5
Это решение не отвечает на оригинальный вопрос
biddulph.r
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.