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


191

Я намагаюся зробити звичай InfoWindowпісля натискання на маркер за допомогою нового API Карт Google v2. Я хочу, щоб це було схоже на оригінальну програму Google від карт. Подобається це:

Приклад зображення

Коли у мене ImageButtonвсередині, воно не працює - цілий InfoWindowпрокладений і не тільки той ImageButton. Я читав, що це тому, що не існує Viewсамого себе, але це знімок, тому окремі предмети не можна відрізнити один від одного.

EDIT: У документації (завдяки Disco S2 ):

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

Але якщо Google ним користується, повинен бути якийсь спосіб зробити це. Хтось має якусь ідею?


"його не працює" не є особливо корисним описом ваших симптомів. Ось зразок проекту, який показує, що у вас є власне інформаційне вікно із зображенням: github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
CommonsWare

8
@CommonsОбережно, я написав причину цього. З оригінальної документації Примітка: Інформаційне вікно, яке намальовано, не є переглядом у прямому ефірі. Перегляд відображається у вигляді зображення (використовуючи View.draw(Canvas)) ... Це означає, що будь-які наступні зміни представлення не відображатимуться інформаційним вікном на карті. Щоб оновити вікно інформації пізніше. Крім того, інформаційне вікно не дотримуватиметься жодної з інтерактивних дій, типових для звичайного перегляду, таких як події дотику чи жестів. Однак ви можете прослухати загальну подію кліків у всьому інформаційному вікні, як описано в розділі нижче. ... у вашому прикладі є лише перегляд тексту
user1943012

Привіт, як у вас з'явилася кнопка "Моє місцезнаходження", яка відображається під панеллю дій, коли в повноекранному режимі? Дякую!
tkblackbelt

45
Я не думаю, що це питання слід закрити. Це законне питання до проблеми, з якою я також стикаюся.
marienke

12
Я бачу це так часто, багато найкорисніших запитань з відповіддю були закриті. Питання може не завжди відповідати точним вимогам належного запитання, але якщо у нас є чітко роз'яснена ПРОБЛЕМА та добре пояснений ВІДПОВІДЬ, то немає підстав для закриття питання. Люди використовують Stackoverflow для обміну знаннями та закриття теми, яка настільки активно та настільки продуктивна, як "поза темою", не здається мені гарною ідеєю ..
Іван

Відповіді:


333

Я сам шукав рішення цієї проблеми, не маючи везіння, тому мені довелося розгорнути своє, яким я хотів би поділитися тут з вами. (Вибачте, будь ласка, мою погану англійську)

Перше, що я спробував - це використовувати добрий старий PopupWindow. Це досить просто - потрібно лише прослухати, OnMarkerClickListenerа потім показати звичай PopupWindowнад маркером. Деякі інші хлопці тут, на StackOverflow, запропонували це рішення, і воно насправді виглядає непогано на перший погляд. Але проблема з цим рішенням з’являється, коли ви починаєте рухати карту. Ви повинні PopupWindowякось самостійно пересуватись, що можливо (прослуховуючи деякі події OnTouch), але IMHO ви не можете зробити так, щоб він виглядав досить добре, особливо на деяких повільних пристроях. Якщо ви це зробите простим способом, він "стрибає" з однієї точки на іншу. Ви також можете використовувати деякі анімації для відшліфування цих стрибків, але таким чином PopupWindowволя завжди буде «крок позаду», де вона повинна бути на карті, що мені просто не подобається.

У цей момент я думав про якесь інше рішення. Я зрозумів, що насправді мені не потрібно стільки свободи - показувати власні власні погляди з усіма можливостями, які поставляються з нею (як, наприклад, анімовані смужки прогресу тощо). Я думаю, що є вагома причина, чому навіть інженери Google не роблять цього в додатку Карти Google. Все, що мені потрібно, - це кнопка чи дві в Інфо вікні, які показуватимуть натиснутий стан та запускатимуть деякі дії при натисканні. Тому я придумав інше рішення, яке розпадається на дві частини:

Перша частина:
Перша частина полягає в тому, щоб можна було зафіксувати натискання на кнопки, щоб викликати певну дію. Моя ідея така:

  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), я спробую це на телефоні пряників, коли у мене є можливість. До цього часу я виявив обмеження, що ви не можете перетягнути карту з того місця, де ваша кнопка на екрані, і переміщувати карту. Можливо, це можливо якось подолати, але зараз я можу з цим жити.

Я знаю, що це некрасивий злом, але я просто не знайшов нічого кращого, і мені потрібна така модель дизайну настільки погано, що це справді буде приводом повернутися до карту 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 () і (лише), якщо вона повертає нуль, викликає getInfoContents (). Якщо ви повернете деякий вигляд з 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 є лінійним розміщенням (чомусь відносний проміжок приймав повну ширину екрана в 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 (дотримуйтесь цього, якщо ви не знаєте, що наMapReady - це Карти> Документація - Початок роботи )

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

ти можеш показати мені свій код? Мені вдалося зареєструвати події на дотику успішно, але не натискати події, тому я перейшов до цієї реалізації. Крім того, вам потрібно належним чином реалізувати рішення select007.
Manish Jangid

Я поділився повною реалізацією. Повідомте мене, якщо у вас є запитання
Manish Jangid

0

Просто міркування, у мене недостатньо досвіду, щоб спробувати це ...) -:

Оскільки GoogleMap - це фрагмент, слід зафіксувати маркер onClick події та показати спеціальний вигляд фрагмента . Фрагмент карти ще буде видно на задньому плані. Хтось пробував? Будь-яка причина, чому вона не могла працювати?

Недоліком є ​​те, що фрагмент карти заморожуватиметься на backgroud, поки не повернеться до нього користувацький інформаційний фрагмент.


5
Я не думаю, що міркувати як відповідь цікаво. Можливо, це повинен бути коментар до оригінального питання. Просто мої думки.
Йохан Карлссон

1
Ця бібліотека github.com/Appolica/InteractiveInfoWindowAndroid робить щось подібне
Деян Геновський

-2

Я створив зразок проекту студії Android для цього питання.

вихідні знімки екрана: -

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

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

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

Завантажити повний вихідний код проекту Натисніть тут

Зверніть увагу: вам потрібно додати свій ключ API в Androidmanifest.xml


5
Краще поділитися кодом через Github / gist замість zip-файлу. Тож ми можемо безпосередньо там перевірити.
Noundla Sandeep

трохи помилки, яку я знайшов, коли ти натискаєш якусь кнопку, всі кнопки натискаються.
Морозов

3
@Noundla та інші: не переймайтеся завантаженням його поштового коду. Це точна копія пасти прийнятої відповіді на це питання.
Ганеш Мохан

1
@ ganesh2shiv вірно, поштовий код марний. Вам не слід додавати копію вставленого коду
Onkar Nene

-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 - це наш власний макет, який відображає вид, який буде замість infowindow. Я щойно додав сюди перегляд тексту. Ви можете додати сюди додатковий вигляд, щоб зробити його як зразок оснащення. Мій 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
Схоже, ти не читав мого питання. Я знаю, як створити спеціальний перегляд всередині вікна. Я не знаю, як зробити власну кнопку всередині і прослухати її події клацання.
користувач1943012

5
Це рішення не відповідає на початкове запитання
biddulph.r
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.