Google Maps Android API v2 - Etkileşimli InfoWindow (orijinal android google haritalarında olduğu gibi)


191

InfoWindowYeni Google Maps API v2 ile bir işaretleyiciyi tıkladıktan sonra özel hale getirmeye çalışıyorum . Google'ın orijinal haritalar uygulamasında görünmesini istiyorum. Bunun gibi:

Örnek Resim

İçimde olduğunda ImageButton, onun çalışmıyor - tüm InfoWindowkesilir ve sadece ImageButton. Ben okudum çünkü birView kendisi anlık görüntü yüzden tek tek öğeler birbirinden ayırt edilemez.

DÜZENLEME: In belgelerine (sayesinde Disco S2 ):

Bilgi pencerelerinin önceki bölümünde belirtildiği gibi, bir bilgi penceresi canlı bir Görünüm değildir, görünüm harita üzerinde bir görüntü olarak oluşturulur. Sonuç olarak, görünümde ayarladığınız dinleyiciler dikkate alınmaz ve görünümün çeşitli bölümlerindeki tıklama olaylarını ayırt edemezsiniz. Özel bilgi pencerenize düğmeler, onay kutuları veya metin girişleri gibi etkileşimli bileşenler yerleştirmemeniz önerilir.

Ancak Google bunu kullanıyorsa, bunu yapmanın bir yolu olmalı. Herhangi bir fikri olan var mı?


"çalışmıyor" belirtilerinizin özellikle yararlı bir tanımı değildir. Resim ile özel bir bilgi penceresine sahip olduğunu gösteren örnek bir proje: github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
CommonsWare

8
@CommonsWare Bunun sebebini yazdım. Orijinal belgelerden Not: Çizilen bilgi penceresi canlı bir görünüm değildir. Görünüm bir görüntü olarak oluşturuluyor (kullanılıyor View.draw(Canvas)) ... Bu, görünümde daha sonra yapılan değişikliklerin haritadaki bilgi penceresine yansıtılmayacağı anlamına gelir. Bilgi penceresini daha sonra güncellemek için Ayrıca, bilgi penceresi dokunma veya hareket olayları gibi normal bir görünüm için tipik olan etkileşimlere uymaz. Bununla birlikte, genel bir tıklama olayını aşağıdaki bölümde açıklandığı gibi tüm bilgi penceresinde dinleyebilirsiniz. ... örneğinizde sadece textview
user1943012

Merhaba, tam ekran modundayken konumum düğmesinin işlem çubuğunun altında görünmesini nasıl sağladınız? Teşekkürler!
tkblackbelt

45
Bu sorunun kapatılması gerektiğini düşünmüyorum. Bu da karşılaştığım bir soruna yasal bir soru.
marienke

12
Bunu çok sık görebiliyorum, cevaplı en yararlı soruların çoğu kapatıldı. Bir soru her zaman uygun bir sorunun tam gerekliliklerine uymayabilir, ancak eğer iyi açıklanmış bir SORUN ve iyi açıklanmış bir CEVAP varsa, o zaman soruyu kapatmak için bir neden yoktur. İnsanlar bilgi alışverişi yapmak ve "konu dışı" kadar aktif ve üretken bir soru dizisini kapatmak için Stackoverflow kullanmak benim için iyi bir fikir gibi görünmüyor ..
John

Yanıtlar:


333

Bu soruna şanssız bir çözüm arıyordum, bu yüzden burada sizinle paylaşmak istediğim kendimi yuvarlamak zorunda kaldım. (Lütfen kötü İngilizcemi affedin) (İngilizce bir başka Çek adamına cevap vermek biraz çılgınca :-))

Denediğim ilk şey iyi bir eski kullanmaktı PopupWindow. Oldukça kolay - kişi sadece işaretçiyi dinlemeli OnMarkerClickListenerve sonra bir özel göstermelidir PopupWindow. StackOverflow'daki diğer bazı kişiler bu çözümü önerdi ve aslında ilk bakışta oldukça iyi görünüyor. Ancak bu çözümdeki sorun, haritayı hareket ettirmeye başladığınızda ortaya çıkıyor. PopupWindowMümkün olan bir şekilde kendinizi hareket ettirmelisiniz (bazı onTouch olaylarını dinleyerek) ama IMHO, özellikle bazı yavaş cihazlarda yeterince iyi görünmesini sağlayamazsınız. Eğer bunu basit bir şekilde bir noktadan diğerine "atlar". Bu atlamaları cilalamak için bazı animasyonlar da kullanabilirsiniz, ancak bu şekilde PopupWindowher zaman "sevmediğim" haritada olması gereken yerde "bir adım" olacak.

Bu noktada başka bir çözüm düşünüyordum. Aslında bu kadar özgürlüğe gerçekten ihtiyacım olmadığını fark ettim - özel görünümlerimi beraberinde gelen tüm olanaklarla göstermek için (animasyonlu ilerleme çubukları gibi). Google mühendislerinin bile bunu Google Haritalar uygulamasında bu şekilde yapmamalarının iyi bir nedeni olduğunu düşünüyorum. Tek ihtiyacım olan InfoWindow'da basılı bir durumu gösterecek ve tıklandığında bazı eylemleri tetikleyecek bir düğme ya da iki. Bu yüzden iki parçaya ayrılan başka bir çözüm buldum:

İlk bölüm:
İlk bölüm, bazı eylemleri tetiklemek için düğmelere tıklamaları yakalayabilmektir. Benim fikrim şöyledir:

  1. InfoWindowAdapter içinde oluşturulan özel infoWindow'a bir referans tutun.
  2. Özel bir ViewGroup içine sarma MapFragment(veya MapView) (benimki MapWrapperLayout olarak adlandırılır)
  3. MapWrapperLayout'S dispatchTouchEvent öğesini geçersiz kılın ve (InfoWindow şu anda gösteriliyorsa) ilk olarak MotionEvents öğesini önceden oluşturulan InfoWindow'a yönlendirin. MotionEvents'i tüketmezse (InfoWindow içindeki herhangi bir tıklanabilir alanı tıklamamış olmanız gibi) o zaman (ve ancak o zaman) olayların MapWrapperLayout'un üst sınıfına inmesini sağlayın, böylece sonunda haritaya teslim edilecektir.

MapWrapperLayout'un kaynak kodu şöyledir:

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

Tüm bunlar InfoView içindeki görünümleri tekrar "canlı" hale getirecektir - OnClickListeners tetiklemeye başlayacaktır.

İkinci kısım: Kalan sorun, açıkça, InfoWindow'unuzun UI değişikliklerini ekranda göremediğinizdir. Bunu yapmak için Marker.showInfoWindow'u manuel olarak aramanız gerekir. Şimdi, InfoWindow'unuzda kalıcı bir değişiklik yaparsanız (düğmenizin etiketini başka bir şeye değiştirmek gibi), bu yeterince iyidir.

Ancak bir düğmeye basılmış durum veya bu tür bir şey göstermek daha karmaşıktır. İlk sorun, (en azından) InfoWindow'un normal düğmenin basılı durumunu göstermesini sağlayamadım. Düğmeye uzun bir süre basmış olsam bile, ekranda henüz basılı kalmadı. Bunun, muhtemelen bilgi pencerelerinde herhangi bir geçici durum göstermemeyi sağlayan harita çerçevesinin kendisi tarafından işlenen bir şey olduğuna inanıyorum. Ama yanılmış olabilirim, bunu bulmaya çalışmadım.

Yaptığım başka bir kötü kesmek - ekli bir OnTouchListener Düğmeye bir ekledim ve düğmeye basıldığında veya iki özel çekmeceye bırakıldığında manuel olarak arka planını değiştirdim - biri normal durumda ve diğeri basılı durumda. Bu çok hoş değil, ama işe yarıyor :). Artık düğmenin ekranda normalden basılı durumlara geçişini görebiliyordum.

Hala son bir aksaklık var - düğmeyi çok hızlı tıklatırsanız, basılı durumu göstermez - sadece normal durumunda kalır (tıklamanın kendisi tetiklenir, ancak düğme "çalışır"). En azından Galaxy Nexus'umda böyle görünüyor. Yaptığım son şey, düğmeye basıldığında düğmeyi biraz geciktirdim. Bu da oldukça çirkin ve bazı eski, yavaş cihazlarda nasıl çalışacağından emin değilim ama harita çerçevesinin bile böyle bir şey yaptığını sanıyorum. Bunu kendiniz deneyebilirsiniz - InfoWindow'un tamamını tıkladığınızda, basılı bir durumda biraz daha uzun kalır, sonra normal düğmeler yapar (tekrar - en azından telefonumda). Aslında bu, orijinal Google Haritalar uygulamasında bile böyle çalışır.

Neyse, düğmelerdeki durum değişikliklerini ve bahsettiğim diğer şeyleri işleyen özel bir sınıf yazdım, işte kod:

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

İşte kullandığım özel bir InfoWindow düzeni dosyası:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_vertical" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginRight="10dp" >

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:text="Title" />

        <TextView
            android:id="@+id/snippet"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="snippet" />

    </LinearLayout>

    <Button
        android:id="@+id/button" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

Test etkinlik düzeni dosyası ( MapFragmentiçinde olmak 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>

Ve son olarak, tüm bunları bir araya getiren bir test etkinliğinin kaynak kodu:

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

Bu kadar. Şimdiye kadar bunu sadece Galaxy Nexus (4.2.1) ve Nexus 7 (ayrıca 4.2.1) üzerinde test ettim, bir şansım olduğunda bazı Gingerbread telefonlarında deneyeceğim. Şimdiye kadar bulduğum bir sınırlama, haritayı ekranınızdaki düğmenin olduğu yerden sürükleyememeniz ve haritayı hareket ettirememenizdir. Muhtemelen bir şekilde aşılabilir ama şimdilik bununla yaşayabilirim.

Bunun çirkin bir hack olduğunu biliyorum ama daha iyi bir şey bulamadım ve bu tasarım desenine o kadar kötü ihtiyacım var ki, bu gerçekten harita v1 çerçevesine geri dönmek için bir neden olacaktır (ki btw. Gerçekten kaçınmak istiyorum) parçaları vb. ile yeni bir uygulama için). Google'ın neden geliştiricilere InfoWindows'da bir düğmeye sahip olmanın resmi bir yolunu sunmadığını anlamıyorum. Bu yaygın bir tasarım deseni, üstelik bu desen resmi Google Haritalar uygulamasında bile kullanılıyor :). InfoWindows'da yalnızca görüşlerinizi "canlı" hale getirememelerinin nedenlerini anlıyorum - bu muhtemelen haritayı hareket ettirirken ve kaydırırken performansı öldürür. Ancak, bu etkiyi görünüm kullanmadan elde etmenin bir yolu olmalı.


6
ilginç bir çözüm. Bunu denemek istiyorum. Performans nasıldı?
Patrick

10
değiştirmeniz gerekiyor view.setBackground(bgDrawablePressed);ile if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }, Android Gingerbread içinde işe Not: bir daha oluşumu var view.setBackgroundkodda.
Balaji

4
KK_07k11A0585: InfoWindowAdapter uygulamanız muhtemelen yanlış görünüyor. Geçersiz kılmanın iki yöntemi vardır: getInfoWindow () ve getInfoContents (). Çerçeve önce getInfoWindow () yöntemini çağırır ve (yalnızca) null değerini döndürürse getInfoContents () yöntemini çağırır. Bazı Görünüm'ü getInfoWindow'dan döndürürseniz, çerçeve bunu varsayılan bilgi penceresi çerçevesinin içine bırakır - bu durumda istemezsiniz. Yani sadece getInfoWindow null döndürmek ve getInfoContent gelen View döndürmek ve o zaman iyi olmalı.
chose007

18
Eğer ilgilenen varsa, bu çözümü kendi uygulamamda kullanıyorum - CG Transit (Google Play'de bulabilirsiniz). İki ay sonra on binlerce kullanıcı tarafından kullanıldı ve henüz kimse şikayet etmedi.
chose007

2
Standart bir bilgi alanı kullanmıyorsanız, alt ofseti nasıl belirleyebilirsiniz?
Rarw

12

Bu sorunun zaten eski olduğunu görüyorum ama yine de ...

İstediğimizi elde etmek için şirketimizde bir kütüphane oluşturduk - Görünümlü ve her şeyle etkileşimli bir bilgi penceresi. Github'da kontrol edebilirsiniz .

Umut ediyorum bu yardım eder :)


Kümelerle kullanmak mümkün müdür?
gcolucci

9

İşte benim sorunum. AbsoluteLayoutBilgi Penceresi (etkileşim ve çizim yeteneklerinin her bitiyle düzenli bir görünüm) içeren bir kaplama oluştururum . Sonra Handlerher 16 ms'de bir bilgi penceresinin konumunu haritadaki nokta konumu ile senkronize eder. Çılgınca geliyor, ama aslında işe yarıyor.

Demo video: https://www.youtube.com/watch?v=bT9RpH4p9mU (aynı anda çalışan emülatör ve video kaydı nedeniyle performansın düştüğünü dikkate alın).

Demo kodu: https://github.com/deville/info-window-demo

Ayrıntıları sağlayan bir makale (Rusça): http://habrahabr.ru/post/213415/


Bu haritayı yavaşlatacak /
gecikecek

2

choose007'sCevap alamayanlar için

Eğer clickListenerher daim düzgün çalışmıyor chose007'sçözümü, uygulamaya çalışıyorumView.onTouchListener yerine clickListener. Herhangi bir eylemi kullanarak ACTION_UPveya dokunma olayını gerçekleştirin ACTION_DOWN. Bazı nedenlerden dolayı, haritalar infoWindowgönderilirken bazı garip davranışlara neden olur 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;
          }

Düzenleme: Bu nasıl adım adım yaptım

İlk önce kendi bilgi alanınızı (global değişken) aktivitenizde / parçanızda şişirin. Benimki parça içinde. Ayrıca, bilgi düzeni düzeninizdeki kök görünümünün doğrusal düzen olduğundan emin olun (bir nedenden ötürü göreli bilgi dizisi, bilgi düzeyindeki ekranın tamamını kaplıyor)

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;

Sonra google maps android api onMapReady geri arama (onMapReady ne olduğunu bilmiyorsanız bunu takip edin Haritalar> Belgeler - Başlarken )

   @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 başlatma http://stackoverflow.com/questions/14123243/google-maps-android-api-v2- interaktif-infowindow benzeri orijinal-android-go / 15040761 # 15040761 39 - varsayılan işaretçi yüksekliği 20 - varsayılan InfoWindow alt kenarı ve içeriği alt kenarı * /

        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 yöntemi

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

İşaretçi tıklamasını ayrı olarak işleme

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

bana kodunu gösterebilir misin Dokunma olaylarını başarıyla kaydedebildim, ancak olayları tıklayamadım, bu yüzden bu uygulamaya gittim. Ayrıca, select007'nin çözümünü doğru bir şekilde uygulamanız gerekir.
Manish Jangid

Uygulamamın tamamını paylaştım. Herhangi bir sorunuz varsa bize bildirin
Manish Jangid

0

Sadece bir spekülasyon, denemek için yeterli deneyime sahip değilim ...) -:

GoogleMap bir parça olduğu için ,Click etkinliğinde işaretleyici yakalamak ve özel parça göstermek mümkün olmalıdır görünümü . Bir harita parçası arka planda görünmeye devam edecektir. Kimse denedi mi? Çalışamamasının bir nedeni var mı?

Dezavantajı, harita parçasının, özel bir bilgi parçası kontrolünü ona iade edene kadar kağıt üzerinde donmasıdır.


5
Bir spekülasyonu cevap olarak yayınlamanın ilginç olduğunu düşünmüyorum. Belki de orijinal soruya bir yorum olmalı. Sadece düşüncelerim.
Johan Karlsson

1
Bu kütüphane github.com/Appolica/InteractiveInfoWindowAndroid benzer bir şey yapıyor
Deyan Genovski

-2

Bu soru için örnek bir android stüdyo projesi yaptım.

çıktı ekran görüntüleri: -

resim açıklamasını buraya girin

resim açıklamasını buraya girin

resim açıklamasını buraya girin

Tam proje kaynak kodunu indirin Buraya tıklayın

Lütfen dikkat: API anahtarınızı Androidmanifest.xml dosyasına eklemelisiniz


5
Kodunuzu zip dosyası yerine Github / gist ile paylaşmak daha iyidir. Böylece doğrudan orayı kontrol edebiliriz.
Noundla Sandeep

u küçük bir hata buldum, u bazı düğmeye bastığınızda, tüm düğmeler tıklanır.
Morozov

3
@Noundla ve diğerleri: sıkıştırılmış kodunu indirmeyi zahmet etmeyin. Bu soru için kabul edilen cevabın tam bir kopyasını yapıştırın.
Ganesh Mohan

1
@ ganesh2shiv doğru, sıkıştırılmış kod işe yaramaz. Kopyalanmış yapıştırılan kod
eklenmemelidir

-7

Gerçekten çok basit.

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;

            }

        });

Sınıfınıza GoogleMap kullandığınız yere yukarıdaki kodu eklemeniz yeterlidir. R.layout.info_window_layout, bilgi alanının yerine gelecek görünümü gösteren özel düzenimizdir. Buraya metin görünümünü yeni ekledim. Örnek eklenti gibi yapmak için buraya ek görünüm ekleyebilirsiniz. İnfo_window_layout'um şöyleydi:

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

Umarım yardımcı olur. Özel bir bilgi dizisinin çalışan bir örneğini şu adreste bulabilirsiniz: http://wptrafficanalyzer.in/blog/customizing-infowindow-contents-in-google-map-android-api-v2-using-infowindowadapter/#comment-39731

DÜZENLENMİŞ: Bu kod, infoWindow'da nasıl özel görünüm ekleyebileceğimizi gösterir. Bu kod, Özel Görünüm öğelerine yapılan tıklamaları işlemedi. Bu yüzden cevaplamaya yakın ama tam olarak cevap değil, bu yüzden cevap olarak kabul edilmiyor.


İşaretçileri oluşturduğunuz getInfoContents ve getInfoWindow'u geçersiz kılıyor musunuz? Örneğin, farklı tür işaretçiler ekleyip farklı yöntemler kullanıyorsam, farklı işaretleyicileri oluşturduğum bu yöntemlerin her birinin gövdesi içinde geçersiz kılınır mıyım?
Rarw

Evet getInfoContents ve getInfoWindow'u geçersiz kıldım.
Zeeshan Mirza

Sadece bunu denedim ve diğer xml düzenini şişirmek gibi jus çalışır - iyi iş
Rarw

31
Sorumu okumadınız gibi görünüyor. Bilgi alanı içinde özel görünüm oluşturmayı biliyorum. Hangi bilmiyorum içinde özel düğme yapmak ve onun tıklama olayları dinlemek.
user1943012

5
Bu çözüm orijinal soruyu cevaplamıyor
biddulph.r
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.