Google Maps Android API v2-インタラクティブなInfoWindow(元のAndroidのGoogleマップと同様)


191

InfoWindow新しいGoogle Maps API v2でマーカーをクリックした後にカスタムを作成しようとしています。Googleのオリジナルの地図アプリケーションのように見せたいです。このような:

画像の例

私がImageButton中にいるとき、それは機能していません-全体InfoWindowだけでなく、全体が選択されていImageButtonます。Viewそれ自体は存在しないがスナップショットなので、個々のアイテムを区別できないからだと読んだ。

EDIT:ドキュメント(のおかげディスコS2):

情報ウィンドウに関する前のセクションで述べたように、情報ウィンドウはライブビューではなく、ビューが画像としてマップにレンダリングされます。その結果、ビューに設定したリスナーは無視され、ビューのさまざまな部分のクリックイベントを区別できなくなります。カスタム情報ウィンドウ内にボタン、チェックボックス、テキスト入力などのインタラクティブなコンポーネントを配置しないことをお勧めします。

しかしグーグルがそれを使うなら、それを作る何らかの方法がなければならない。誰かが何か考えを持っていますか?


「機能しない」は、症状の特に有用な説明ではありません。画像付きのカスタム情報ウィンドウがあることを示すサンプルプロジェクトを次に示します。github.com
commonsguy

8
@CommonsWare私はその理由を書いた。元のドキュメントから注:描画される情報ウィンドウはライブビューではありません。ビューはイメージとしてレンダリングされます(を使用View.draw(Canvas))...これは、ビューに対するその後の変更は、マップ上の情報ウィンドウに反映されないことを意味します。後で情報ウィンドウを更新するにはさらに、情報ウィンドウは、タッチやジェスチャーイベントなどの通常のビューに典型的な対話性を考慮しません。ただし、以下のセクションで説明するように、情報ウィンドウ全体で一般的なクリックイベントをリッスンできます。...例では、textviewのみです
user1943012

こんにちは。フルスクリーンモードで、ロケーションボタンをアクションバーの下に表示するにはどうすればよいですか。ありがとう!
tkblackbelt 2013

45
この質問は閉じるべきではないと思います。私が直面している問題に対する正当な質問です。
marienke 2014年

12
私はこれを頻繁に見ることができ、回答のある最も有用な質問の多くは閉じられました。質問は、適切な質問の正確な要件に必ずしも適合しない場合がありますが、十分に説明された問題と十分に説明された回答がある場合、質問を閉じる理由はありません。人々は、為替知識へのStackOverflowを使用するので、積極的かつ生産的なので、「オフトピック」..私には良いアイデアのように思われないようである質問スレッド終了
ジョン

回答:


333

私はこの問題の解決策を自分で運がなかったので探していたので、自分で転がさなければならなかったので、ここで共有します。(私の悪い英語を許しなさい)(英語で別のチェコ人に答えることは少しおかしいです:-))

私が最初に試みたのは、古き良きものを使うことでしたPopupWindow。それは非常に簡単です-を聞いて、マーカーの上にOnMarkerClickListenerカスタムを表示するだけPopupWindowです。ここStackOverflowの他の何人かがこの解決策を提案しましたが、実際には一見すると非常によく見えます。しかし、このソリューションの問題は、マップを移動し始めたときに明らかになります。PopupWindow(いくつかのonTouchイベントをリッスンすることによって)どうにかして自分で移動する必要がありますが、特に一部の低速デバイスでは、見た目を十分に良くすることができません。単純な方法で行うと、ある場所から別の場所に「ジャンプ」します。アニメーションを使用してジャンプを洗練することもできますが、このようにするPopupWindowと、マップ上にあるはずのない場所では、常に「一歩遅れ」になります。

この時点で、私は他の解決策について考えていました。私は実際にはそれほど多くの自由が必要ではないことに気づきました-アニメーションプログレスバーなどのすべての可能性を備えたカスタムビューを表示するには。グーグルのエンジニアでさえ、Googleマップアプリでこの方法でこれを行わないのには十分な理由があると思います。必要なのは、InfoWindowの1つまたは2つのボタンだけで、押された状態を表示し、クリックするといくつかのアクションをトリガーします。だから私は2つの部分に分かれる別の解決策を思いつきました:

最初の部分:
最初の部分は、ボタンのクリックをキャッチして何らかのアクションをトリガーできるようにすることです。私の考えは次のとおりです。

  1. InfoWindowAdapterで作成されたカスタムinfoWindowへの参照を保持します。
  2. カスタムViewGroup内にMapFragment(またはMapView)をラップします(私はMapWrapperLayoutと呼ばれます)
  3. MapWrapperLayoutのdispatchTouchEventをオーバーライドし、(現在InfoWindowが表示されている場合)最初にMotionEventを以前に作成したInfoWindowにルーティングします。(InfoWindow内のクリック可能な領域をクリックしなかったなどの理由で)MotionEventsを消費しない場合(そしてその場合のみ)、イベントを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がトリガーを開始します。

2番目の部分: 残りの問題は、InfoWindowのUIの変更が画面に表示されないことです。そのためには、Marker.showInfoWindowを手動で呼び出す必要があります。これで、InfoWindowで永続的な変更(ボタンのラベルを別のものに変更するなど)を実行する場合、これで十分です。

しかし、ボタンが押された状態やその性質を示すことは、より複雑です。最初の問題は、(少なくとも)InfoWindowに通常のボタンが押された状態を表示させることができなかったことです。ボタンを長押ししても画面上で押されていない状態です。これは、マップフレームワーク自体によって処理されるものであり、情報ウィンドウに一時的な状態が表示されないようにするためのものです。しかし、私は間違っている可能性があり、私はこれを見つけようとしませんでした。

私がやったのは別の厄介なハックです- OnTouchListenerボタンにを取り付け、ボタンが押されたとき、またはボタンが2つのカスタムドローアブルに解放されたときに手動で背景を切り替えました-1つは通常の状態のボタン、もう1つは押された状態のボタンです。これはあまり良くありませんが、動作します:)。これで、ボタンが通常の状態から押された状態に切り替わるのを画面で確認できました。

まだ最後のグリッチが1つあります。ボタンのクリックが速すぎると、押された状態が表示されず、通常の状態のままになります(クリック自体が発生してボタンが「機能する」ため)。少なくとも、これは私のGalaxy Nexusに表示される方法です。それで私が最後にしたことは、ボタンが押された状態でボタンを少し遅らせたことです。これも非常に醜く、古い、遅いデバイスでどのように機能するのかはわかりませんが、マップフレームワーク自体でもこのようなことをしているのではないかと思います。自分で試してみることができます。InfoWindow全体をクリックすると、押された状態が少し長くなり、その後、通常のボタンと同じように(少なくとも、私の電話では)実行されます。そして、これは実際には元のGoogleマップアプリでも機能します。

とにかく、私は自分でボタンの状態の変更やその他のすべてのことを処理するカスタムクラスを自分で作成したので、コードは次のとおりです。

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マップアプリでも使用されています:)。InfoWindowsでビューを「ライブ」にすることができない理由を理解しています。これは、マップを移動したりスクロールしたりすると、パフォーマンスが低下する可能性があります。しかし、ビューを使用せずにこの効果を実現する方法がいくつかあるはずです。


6
興味深い解決策。やってみたいです。パフォーマンスはいかがでしたか?
Patrick

10
交換する必要があるview.setBackground(bgDrawablePressed);if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }、Androidのジンジャーブレッドで動作するように注意を:の1つの以上発生していview.setBackgroundたコードでは。
Balaji 2013年

4
KK_07k11A0585:InfoWindowAdapterの実装がおそらく間違っているようです。オーバーライドする2つのメソッドがあります:getInfoWindow()とgetInfoContents()。フレームワークは最初にgetInfoWindow()メソッドを呼び出し、(のみ)nullを返す場合はgetInfoContents()を呼び出します。getInfoWindowから一部のビューを返す場合、フレームワークはそれをデフォルトの情報ウィンドウフレーム内に配置します。したがって、getInfoWindowからnullを返し、getInfoContentからViewを返すだけで問題ありません。
2007

18
誰かが興味を持っている場合、私は自分のアプリ-CG Transit(Google Playで見つけることができます)でこのソリューションを使用しています。2か月後、それは数万人のユーザーによって使用されており、誰もまだそれについて不満を言っていません。
chose007

2
標準の情報ウィンドウを使用していない場合、どのように下部オフセットを決定しますか?
Rarw

12

この質問はもう古いですが、それでも...

私たちは会社で希望どおりのことを達成するためにsipmleライブラリを作成しました-ビューとすべてを備えたインタラクティブな情報ウィンドウ。githubで確認できます。

それが役に立てば幸いです:)


クラスタで使用できますか?
gcolucci 2017年

9

これが私の問題です。AbsoluteLayout情報ウィンドウ(あらゆる対話機能と描画機能を備えた通常のビュー)を含むオーバーレイを作成します。それから始めますHandler、情報ウィンドウの位置を16ミリ秒ごとに地図上のポイントの位置と同期させます。クレイジーに聞こえますが、実際には機能します。

デモビデオ: https //www.youtube.com/watch?v=bT9RpH4p9mU(エミュレータとビデオ録画が同時に実行されているため、パフォーマンスが低下することを考慮してください)。

デモのコード: https //github.com/deville/info-window-demo

詳細を提供する記事(ロシア語):http : //habrahabr.ru/post/213415/


これにより、マップのスクロールが遅くなったり遅れたりします
Shane Ekanayake

2

choose007's答えを出して実行できなかった人のために

clickListenerchose007'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レイアウトのルートビューがlinearlayoutであることを確認してください(何らかの理由で、relativelayoutはinfowindowの画面の全幅を占めていました)

infoWindow = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.info_window, null);
/* Other global variables used in below code*/
private HashMap<Marker,YourData> mMarkerYourDataHashMap = new HashMap<>();
private GoogleMap mMap;
private MapWrapperLayout mapWrapperLayout;

次に、Google Maps Android APIのonMapReadyコールバックで(onMapReadyが何であるかわからない場合は、マップ>ドキュメント-はじめに

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

MapWrapperLayout初期化 http://stackoverflow.com/questions/14123243/google-maps-android-api-v2- interactive-infowindow-like-in-original-android-go / 15040761#15040761 39-デフォルトのマーカーの高さ20-間のオフセットデフォルトのInfoWindowの下端とそのコンテンツの下端* /

        mapWrapperLayout.init(mMap, Utils.getPixelsFromDp(mContext, 39 + 20));

        /*handle marker clicks separately - not necessary*/
       mMap.setOnMarkerClickListener(this);

       mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
                @Override
                public View getInfoWindow(Marker marker) {
                    return null;
                }

            @Override
            public View getInfoContents(Marker marker) {
                YourData data = mMarkerYourDataHashMap.get(marker);
                setInfoWindow(marker,data);
                mapWrapperLayout.setMarkerWithInfoWindow(marker, infoWindow);
                return infoWindow;
            }
        });
    }

SetInfoWindowメソッド

private void setInfoWindow (final Marker marker, YourData data)
            throws NullPointerException{
        if (data.getVehicleNumber()!=null) {
            ((TextView) infoWindow.findViewById(R.id.VehicelNo))
                    .setText(data.getDeviceId().toString());
        }
        if (data.getSpeed()!=null) {
            ((TextView) infoWindow.findViewById(R.id.txtSpeed))
                    .setText(data.getSpeed());
        }

        //handle dispatched touch event for view click
        infoWindow.findViewById(R.id.any_view).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                int action = MotionEventCompat.getActionMasked(event);
                switch (action) {
                    case MotionEvent.ACTION_UP:
                        Log.d(TAG,"any_view clicked" );
                        break;
                }
                return true;
            }
        });

マーカーのクリックを個別に処理する

    @Override
    public boolean onMarkerClick(Marker marker) {
        Log.d(TAG,"on Marker Click called");
        marker.showInfoWindow();
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(marker.getPosition())      // Sets the center of the map to Mountain View
                .zoom(10)
                .build();
        mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition),1000,null);
        return true;
    }

コードを見せていただけますか?タッチイベントは正常に記録できましたが、クリックイベントは記録できなかったため、この実装に進みました。また、choose007のソリューションを適切に実装する必要があります。
Manish Jangid、2016年

完全な実装を共有しました。ご
不明な点

0

単なる憶測ですが、私はそれを試す十分な経験がありません...)-:

GoogleMapはフラグメントであるため、マーカーのonClickイベントをキャッチし、カスタムフラグメントビューを表示できるはずです。マップフラグメントは引き続き背景に表示されます。誰かがそれを試しましたか?それがうまくいかなかった理由は何ですか?

欠点は、カスタム情報フラグメントが制御を返すまで、マップフラグメントが背景でフリーズすることです。


5
答えとして投機を投稿するのは面白いとは思いません。多分それは元の質問へのコメントでなければなりません。ただ私の考え。
Johan Karlsson、2015年

1
このライブラリgithub.com/Appolica/InteractiveInfoWindowAndroidも同様のことを行います
Deyan Genovski

-2

この質問のためにサンプルのAndroid Studioプロジェクトを作成しました。

出力スクリーンショット:-

ここに画像の説明を入力してください

ここに画像の説明を入力してください

ここに画像の説明を入力してください

完全なプロジェクトソースコードをダウンロードするには、ここをクリックして ください

ご注意ください: APImanキーをAndroidmanifest.xmlに追加する必要があります


5
zipファイルではなく、Github / gistを介してコードを共有することをお勧めします。そこで直接チェックできます。
Noundla Sandeep 2017

私が見つけた小さなバグ、いくつかのボタンを押すと、すべてのボタンがクリックされます。
モロゾフ

3
@Noundlaなど:彼のzipコードをダウンロードする必要はありません。これは、この質問に対する受け入れられた回答の正確なコピーペーストです。
ガネーシャモハン

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をオーバーライドします。
Zeeshan Mirza、2013

これを試してみると、他のxmlレイアウトを膨らませるように機能します-よくできました
Rarw

31
私の質問を読んでいないようです。infowindow内にカスタムビューを作成する方法を知っています。私が知らないのは、内部にカスタムボタンを作成し、そのクリックイベントをリッスンする方法です。
user1943012 2013年

5
このソリューションは元の質問に答えません
biddulph.r 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.