Google Maps Android API v2 - InfoWindow Interaktif (seperti di peta google android asli)


191

Saya mencoba membuat kustom InfoWindowsetelah mengklik penanda dengan Google Maps API v2 baru. Saya ingin terlihat seperti di aplikasi peta asli oleh Google. Seperti ini:

Contoh Gambar

Ketika saya ada ImageButtondi dalam, itu tidak berfungsi - seluruh InfoWindowslected dan bukan hanya ImageButton. Saya membaca bahwa itu karena tidak ada Viewsendiri tetapi snapshot, sehingga item individual tidak dapat dibedakan satu sama lain.

EDIT: Dalam dokumentasi (terima kasih kepada S2 Disko ):

Seperti yang disebutkan di bagian sebelumnya pada info windows, jendela info bukanlah tampilan langsung, melainkan tampilan yang ditampilkan sebagai gambar di peta. Akibatnya, setiap pendengar yang Anda setel pada tampilan diabaikan dan Anda tidak dapat membedakan antara peristiwa klik pada berbagai bagian tampilan. Anda disarankan untuk tidak menempatkan komponen interaktif - seperti tombol, kotak centang, atau input teks - di dalam jendela info khusus Anda.

Tetapi jika Google menggunakannya, pasti ada beberapa cara untuk membuatnya. Adakah yang punya ide?


"ini tidak berfungsi" bukanlah deskripsi yang berguna untuk gejala Anda. Berikut adalah contoh proyek yang memperlihatkan memiliki jendela info khusus dengan gambar: github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
CommonsWare

8
@ CommonsWare saya menulis alasannya. Dari dokumentasi asli Catatan: Jendela info yang digambar bukan tampilan langsung. Tampilan ditampilkan sebagai gambar (menggunakan View.draw(Canvas)) ... Ini berarti bahwa setiap perubahan berikutnya pada tampilan tidak akan tercermin oleh jendela info di peta. Untuk memperbarui jendela info di lain waktu. Selanjutnya, jendela info tidak akan menghargai interaktivitas apa pun yang khas untuk tampilan normal seperti acara sentuh atau gerakan. Namun Anda dapat mendengarkan acara klik umum pada seluruh jendela info seperti dijelaskan di bagian di bawah ini. ... dalam contoh Anda hanya tampilan teks
user1943012

Hai, bagaimana Anda mendapatkan tombol lokasi saya muncul di bawah bilah tindakan saat dalam mode layar penuh? Terima kasih!
tkblackbelt

45
Saya tidak berpikir bahwa pertanyaan ini harus ditutup. Itu pertanyaan sah untuk masalah yang juga saya hadapi.
marienke

12
Saya bisa melihat ini begitu sering, banyak pertanyaan paling berguna dengan jawaban telah ditutup. Sebuah pertanyaan mungkin tidak selalu sesuai dengan persyaratan yang tepat dari pertanyaan yang tepat tetapi jika kita memiliki MASALAH yang dijelaskan dengan baik dan JAWABAN yang dijelaskan dengan baik maka tidak ada alasan untuk menutup pertanyaan. Orang-orang menggunakan Stackoverflow untuk bertukar pengetahuan dan menutup utas pertanyaan yang begitu aktif dan sangat produktif sebagai "di luar topik" sepertinya bukan ide yang baik untuk saya ..
John

Jawaban:


333

Saya mencari solusi untuk masalah ini sendiri tanpa hasil, jadi saya harus memutar sendiri yang ingin saya bagikan di sini dengan Anda. (Maafkan bahasa Inggris saya yang buruk) (Agak gila menjawab orang Ceko lain dalam bahasa Inggris :-))

Hal pertama yang saya coba adalah menggunakan yang lama PopupWindow. Ini cukup mudah - Anda hanya perlu mendengarkan OnMarkerClickListenerdan kemudian menampilkan kebiasaan di PopupWindowatas penanda. Beberapa orang lain di sini di StackOverflow menyarankan solusi ini dan itu sebenarnya terlihat cukup baik pada pandangan pertama. Tetapi masalah dengan solusi ini muncul ketika Anda mulai memindahkan peta. Anda harus memindahkan PopupWindowsendiri entah bagaimana yang mungkin (dengan mendengarkan beberapa acara onTouch) tetapi IMHO Anda tidak dapat membuatnya terlihat cukup baik, terutama pada beberapa perangkat yang lambat. Jika Anda melakukannya dengan cara sederhana "melompat" dari satu tempat ke tempat lain. Anda juga bisa menggunakan beberapa animasi untuk memoles lompatan-lompatan itu tetapi dengan cara PopupWindowini selalu akan menjadi "langkah di belakang" di mana seharusnya berada di peta yang saya tidak suka.

Pada titik ini, saya sedang memikirkan beberapa solusi lain. Saya menyadari bahwa saya sebenarnya tidak benar-benar membutuhkan banyak kebebasan - untuk menunjukkan pandangan khusus saya dengan semua kemungkinan yang menyertainya (seperti bilah kemajuan animasi, dll.). Saya pikir ada alasan bagus mengapa bahkan para insinyur google tidak melakukannya dengan cara ini di aplikasi Google Maps. Yang saya butuhkan adalah satu atau dua tombol di InfoWindow yang akan menampilkan keadaan tertekan dan memicu beberapa tindakan saat diklik. Jadi saya datang dengan solusi lain yang terbagi menjadi dua bagian:

Bagian pertama:
Bagian pertama adalah dapat menangkap klik pada tombol untuk memicu beberapa tindakan. Ide saya adalah sebagai berikut:

  1. Simpan referensi ke infoWindow khusus yang dibuat di InfoWindowAdapter.
  2. Bungkus MapFragment(atau MapView) di dalam ViewGroup khusus (milik saya disebut MapWrapperLayout)
  3. Mengganti MapWrapperLayoutdispatchTouchEvent dan (jika InfoWindow saat ini ditampilkan) pertama rute MotionEvents ke InfoWindow yang dibuat sebelumnya. Jika tidak menggunakan MotionEvents (seperti karena Anda tidak mengklik area yang dapat diklik di dalam InfoWindow dll.) Maka (dan hanya kemudian) biarkan acara turun ke superclass MapWrapperLayout sehingga akhirnya akan dikirim ke peta.

Berikut adalah kode sumber 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);
    }
}

Semua ini akan membuat tampilan di dalam InfoView "live" kembali - OnClickListeners akan mulai memicu dll.

Bagian kedua: Masalah yang tersisa adalah, yang jelas, Anda tidak dapat melihat perubahan UI dari InfoWindow Anda di layar. Untuk melakukan itu, Anda harus memanggil Marker.showInfoWindow secara manual. Sekarang, jika Anda melakukan beberapa perubahan permanen di InfoWindow Anda (seperti mengubah label tombol Anda ke yang lain), ini sudah cukup baik.

Tetapi menunjukkan keadaan tombol ditekan atau sesuatu yang sifatnya lebih rumit. Masalah pertama adalah, bahwa (setidaknya) saya tidak dapat membuat InfoWindow menunjukkan status tombol yang ditekan normal. Bahkan jika saya menekan tombol untuk waktu yang lama, itu tetap tidak ditekan di layar. Saya percaya ini adalah sesuatu yang ditangani oleh kerangka peta itu sendiri yang mungkin memastikan untuk tidak menampilkan keadaan sementara di jendela info. Tapi saya bisa saja salah, saya tidak mencoba mencari tahu.

Apa yang saya lakukan adalah hack jahat lainnya - saya lampirkan OnTouchListener tombol dan secara manual beralih latar belakang ketika tombol ditekan atau dilepaskan ke dua drawables kustom - satu dengan tombol dalam keadaan normal dan yang lain dalam keadaan ditekan. Ini tidak terlalu bagus, tetapi berhasil :). Sekarang saya bisa melihat tombol beralih antara kondisi normal ke kondisi ditekan di layar.

Masih ada satu kesalahan terakhir - jika Anda mengklik tombol terlalu cepat, itu tidak menunjukkan keadaan ditekan - itu hanya tetap dalam keadaan normal (meskipun klik itu sendiri dipicu sehingga tombol "berfungsi"). Setidaknya begitulah yang muncul di Galaxy Nexus saya. Jadi hal terakhir yang saya lakukan adalah saya menunda sedikit tombol dalam keadaan ditekan. Ini juga sangat jelek dan saya tidak yakin bagaimana cara kerjanya pada beberapa perangkat yang lebih tua, lambat tapi saya menduga bahwa bahkan kerangka peta itu sendiri melakukan sesuatu seperti ini. Anda dapat mencobanya sendiri - ketika Anda mengklik seluruh InfoWindow, ia tetap dalam keadaan ditekan sedikit lebih lama, kemudian tombol normal melakukannya (lagi - setidaknya di ponsel saya). Dan ini sebenarnya cara kerjanya bahkan di aplikasi Google Maps yang asli.

Lagi pula, saya menulis sendiri kelas khusus yang menangani perubahan status tombol dan semua hal lain yang saya sebutkan, jadi di sini adalah kodenya:

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

Berikut adalah file tata letak InfoWindow khusus yang saya gunakan:

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

Menguji file tata letak aktivitas ( MapFragmentberada di dalam 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>

Dan akhirnya kode sumber dari aktivitas pengujian, yang menempelkan semua ini bersama-sama:

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

Itu dia. Sejauh ini saya hanya menguji ini pada Galaxy Nexus saya (4.2.1) dan Nexus 7 (juga 4.2.1), saya akan mencobanya pada beberapa ponsel Gingerbread ketika saya memiliki kesempatan. Keterbatasan yang saya temukan sejauh ini adalah bahwa Anda tidak dapat menyeret peta dari mana tombol Anda di layar dan memindahkan peta. Mungkin bisa diatasi, tetapi untuk saat ini, saya bisa hidup dengan itu.

Saya tahu ini adalah peretasan yang jelek, tetapi saya tidak menemukan apa pun yang lebih baik dan saya sangat membutuhkan pola desain ini sehingga ini akan menjadi alasan untuk kembali ke kerangka peta v1 (yang sebenarnya. Saya benar-benar ingin menghindari untuk aplikasi baru dengan fragmen dll). Saya hanya tidak mengerti mengapa Google tidak menawarkan pengembang beberapa cara resmi untuk memiliki tombol pada InfoWindows. Ini adalah pola desain yang umum, apalagi pola ini digunakan bahkan di aplikasi Google Maps resmi :). Saya mengerti alasan mengapa mereka tidak bisa membuat tampilan Anda "langsung" di InfoWindows - ini mungkin akan mematikan kinerja saat memindahkan dan menggulir peta. Tetapi harus ada cara bagaimana mencapai efek ini tanpa menggunakan pandangan.


6
solusi menarik. Saya ingin mencoba ini. Bagaimana kinerjanya?
Patrick

10
perlu diganti view.setBackground(bgDrawablePressed);dengan if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }untuk bekerja di Android Gingerbread, Catatan: ada satu lagi kejadian view.setBackgrounddalam kode.
Balaji

4
KK_07k11A0585: Tampaknya implementasi InfoWindowAdapter Anda mungkin salah. Ada dua metode untuk mengganti: getInfoWindow () dan getInfoContents (). Kerangka kerja pertama-tama memanggil metode getInfoWindow () dan (hanya) jika ia mengembalikan null, ia memanggil getInfoContents (). Jika Anda mengembalikan beberapa View dari getInfoWindow, framework akan meletakkannya di dalam bingkai jendela info default - yang mana dalam kasus Anda tidak Anda inginkan. Jadi kembalikan null dari getInfoWindow dan kembalikan View dari getInfoContent dan seharusnya tidak masalah.
Choose007

18
Jika ada yang tertarik, saya menggunakan solusi ini di aplikasi saya sendiri - CG Transit (Anda dapat menemukannya di Google Play). Setelah dua bulan telah digunakan oleh beberapa puluh ribu pengguna dan belum ada yang mengeluhkannya.
Memilih 007

2
bagaimana Anda menentukan offset bawah jika Anda tidak menggunakan infowindow standar?
Rarw

12

Saya melihat bahwa pertanyaan ini sudah lama tetapi masih ...

Kami membuat perpustakaan kecil di perusahaan kami untuk mencapai apa yang diinginkan - Jendela info interaktif dengan tampilan dan segalanya. Anda dapat memeriksanya di github .

Saya harap ini membantu :)


Apakah mungkin untuk menggunakannya dengan cluster?
gcolucci

9

Inilah pendapat saya tentang masalahnya. Saya membuat AbsoluteLayoutoverlay yang berisi Info Window (tampilan reguler dengan setiap sedikit interaktivitas dan kemampuan menggambar). Lalu saya mulai Handleryang menyinkronkan posisi jendela info dengan posisi titik pada peta setiap 16 ms. Kedengarannya gila, tetapi sebenarnya berhasil.

Demo video: https://www.youtube.com/watch?v=bT9RpH4p9mU (perhatikan bahwa kinerjanya menurun karena emulator dan perekaman video berjalan secara bersamaan).

Kode demo: https://github.com/deville/info-window-demo

Artikel yang memberikan rincian (dalam bahasa Rusia): http://habrahabr.ru/post/213415/


Ini akan memperlambat / lag menggulir peta
Shane Ekanayake

2

Bagi mereka yang tidak bisa mendapatkan choose007'sjawaban dan berlari

Jika clickListenertidak bekerja dengan benar setiap saat di chose007'ssolusi, cobalah untuk menerapkan View.onTouchListenerbukan clickListener. Tangani acara sentuh menggunakan salah satu tindakan ACTION_UPatau ACTION_DOWN. Untuk beberapa alasan, peta infoWindowmenyebabkan beberapa perilaku aneh saat dikirim 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;
          }

Sunting: Ini adalah bagaimana saya melakukannya langkah demi langkah

Pertama kembangkan infowindow Anda sendiri (variabel global) di suatu tempat di aktivitas / fragmen Anda. Milik saya berada dalam fragmen. Pastikan juga bahwa tampilan root dalam tata letak infowindow Anda adalah linearlayout (untuk beberapa alasan relativelayout mengambil lebar layar penuh dalam 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;

Kemudian di panggilan balik onMapReady dari google maps android api (ikuti ini jika Anda tidak tahu apa yang onMapReady adalah Maps> Dokumentasi - Memulai )

   @Override
    public void onMapReady(GoogleMap googleMap) {
       /*mMap is global GoogleMap variable in activity/fragment*/
        mMap = googleMap;
       /*Some function to set map UI settings*/ 
        setYourMapSettings();

MapWrapperLayoutinisialisasi http://stackoverflow.com/questions/14123243/google-maps-android-api-v2- interaktif-infowindow-like-in-original-android-go / 15040761 # 15040761 39 - tinggi marker default 20 - offset antara InfoWindow tepi bawah default dan tepi bawah kontennya * /

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

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

Menangani klik penanda secara terpisah

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

dapatkah kamu tunjukkan kodemu padamu? Saya berhasil mencatat acara sentuh tetapi tidak mengklik acara sehingga saya mengikuti implementasi ini. Selain itu, Anda perlu menerapkan solusi select007 dengan benar.
Manish Jangid

Saya membagikan implementasi lengkap saya. Beri tahu saya jika ada pertanyaan
Manish Jangid

0

Hanya spekulasi, saya belum cukup pengalaman untuk mencobanya ...) -:

Karena GoogleMap adalah sebuah fragmen, seharusnya dimungkinkan untuk menangkap penanda di acara Klik dan menampilkan tampilan fragmen khusus . Fragmen peta akan tetap terlihat di latar belakang. Adakah yang mencobanya? Ada alasan mengapa itu tidak bisa berfungsi?

Kerugiannya adalah bahwa fragmen peta akan dibekukan pada backgroud, sampai sebuah fragmen info khusus mengembalikan kontrol padanya.


5
Saya tidak berpikir itu menarik untuk mengirim spekulasi sebagai jawaban. Mungkin itu harus menjadi komentar pada pertanyaan awal. Hanya pikiran saya saja.
Johan Karlsson

1
Perpustakaan ini github.com/Appolica/InteractiveInfoWindowAndroid melakukan hal serupa
Deyan Genovski

-2

Saya telah membuat contoh proyek studio android untuk pertanyaan ini.

tangkapan layar keluaran: -

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Unduh kode sumber proyek lengkap Klik di sini

Harap dicatat: Anda harus menambahkan kunci API Anda di Androidmanifest.xml


5
Lebih baik membagikan kode Anda melalui Github / inti daripada file zip. Jadi kita bisa langsung cek di sana.
Noundla Sandeep

bug kecil yang saya temukan, ketika Anda menekan beberapa tombol, semua tombol diklik.
Morozov

3
@Noundla & lainnya: jangan repot-repot mengunduh kode zip-nya. Ini adalah salinan tepat dari jawaban yang diterima untuk pertanyaan ini.
Ganesh Mohan

1
@ ganesh2shiv benar, kode zip tidak berguna. Anda tidak boleh melampirkan copy paste kode
Onkar Nene

-7

Ini sangat sederhana.

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;

            }

        });

Cukup tambahkan kode di atas di kelas Anda di mana Anda menggunakan GoogleMap. R.layout.info_window_layout adalah tata letak khusus kami yang menampilkan tampilan yang akan menggantikan infowindow. Saya baru saja menambahkan tampilan teks di sini. Anda dapat menambahkan tampilan tambahan di sini untuk membuatnya seperti contoh snap. Info_window_layout saya tadinya

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

Saya harap ini akan membantu. Kita dapat menemukan contoh kerja infowindow khusus di http://wptrafficanalyzer.in/blog/customizing-infowindow-contents-in-google-map-android-api-v2-using-infowindowadapter/#comment-39731

Diedit: Kode ini menunjukkan bagaimana kita dapat menambahkan tampilan kustom di infoWindow. Kode ini tidak menangani klik pada item Tampilan Kustom. Jadi itu dekat dengan jawaban tetapi bukan jawaban yang tepat itu sebabnya tidak diterima sebagai jawaban.


Apakah Anda mengganti getInfoContents dan getInfoWindow tempat Anda membuat marker? Misalnya, jika saya menambahkan berbagai jenis penanda dan menggunakan metode yang berbeda, apakah saya hanya akan menimpa di dalam tubuh masing-masing metode di mana saya membuat penanda yang berbeda?
Rarw

Ya saya mengganti getInfoContents dan getInfoWindow.
Zeeshan Mirza

Baru saja mencoba ini dan berfungsi seperti menggembungkan tata letak xml lainnya - pekerjaan bagus
Rarw

31
Sepertinya Anda tidak membaca pertanyaan saya. Saya tahu cara membuat tampilan khusus di dalam infowindow. Yang saya tidak tahu adalah bagaimana membuat tombol kustom di dalam dan mendengarkan acara klik-nya.
user1943012

5
Solusi ini tidak menjawab pertanyaan awal
biddulph.r
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.