Google Maps Android API v2-交互式信息窗口(例如原始的android Google地图)


191

InfoWindow在使用新的Google Maps API v2单击标记后,我试图进行自定义。我希望它看起来像Google的原始地图应用程序。像这样:

范例图片

当我ImageButton进入内部时,它不起作用-整个InfoWindow被选中,而不仅仅是ImageButton。我读到这是因为没有它View本身,而是快照,所以不能将各个项目区分开。

编辑:文档中(感谢Disco S2):

如上一节有关信息窗口的部分所述,信息窗口不是实时视图,而是将视图作为图像渲染到地图上。因此,您在视图上设置的所有侦听器都将被忽略,并且您无法区分视图各部分上的单击事件。建议您不要在自定义信息窗口中放置交互式组件,例如按钮,复选框或文本输入。

但是,如果Google使用它,则必须有某种方法可以实现它。有人有什么主意吗?


“它不起作用”不是对症状特别有用的描述。这是一个示例项目,显示了一个带有图像的自定义信息窗口:github.com/commonsguy/cw-omnibus/tree/master/MapsV2/Popups
CommonsWare

8
@CommonsWare我写的原因。来自原始文档注意:绘制的信息窗口不是实时视图。该视图将显示为图像(使用View.draw(Canvas))。这意味着该视图的任何后续更改都不会反映在地图上的信息窗口中。以后再更新信息窗口此外,信息窗口将不考虑任何普通的正常视图交互性,例如触摸或手势事件。但是,您可以在整个信息窗口中监听通用的click事件,如以下部分所述。...在您的示例中仅是textview
user1943012 2013年

嗨,在全屏模式下,如何使我的位置按钮显示在操作栏下方?谢谢!
tkblackbelt

45
我认为这个问题不应该解决。对于我也面临的一个问题,这是一个合法的问题。
marienke 2014年

12
我经常看到这种情况,许多最有用的答案问题都已经关闭。一个问题可能并不总是能满足一个适当问题的确切要求,但是如果我们对问题有一个很好的解释,而对答案的解释也很好,那么就没有理由结束这个问题了。人们用#1到交流知识和关闭问题线程是如此积极,如此高效的“题外话”似乎不是一个好主意,我..
约翰

Answers:


333

我本人在寻找一个解决该问题的方法,但是没有运气,所以我不得不自己提出,我想在这里与您分享。(请原谅我的英语不好)(用英语回答另一个捷克人有点疯狂:-))

我试过的第一件事是用一个好旧的PopupWindow。这很容易-只需收听OnMarkerClickListener,然后PopupWindow在标记上方显示自定义即可。StackOverflow上的其他一些人提出了这种解决方案,乍一看它看起来确实不错。但是,当您开始四处移动地图时,就会出现此解决方案的问题。您必须自己移动PopupWindow某种方式(通过侦听一些onTouch事件),但是恕我直言,您无法使其看起来足够好,尤其是在某些慢速设备上。如果您以简单的方式进行操作,它就会从一个点“跳”到另一个点。您还可以使用一些动画来完善这些跳跃,但是这样PopupWindow一来,它始终会“落后于”我应该不喜欢的地图上的位置。

此时,我正在考虑其他解决方案。我意识到我实际上并不需要那么大的自由-用所有可能的显示自己的自定义视图(例如动画进度条等)。我认为,即使Google工程师也没有在Google Maps应用中以这种方式这样做是有充分的理由的。我需要的是在InfoWindow上的一个或两个按钮,该按钮将显示按下状态并在单击时触发一些动作。因此,我提出了另一个解决方案,该解决方案分为两个部分:

第一部分:
第一部分是能够捕获按钮上的单击以触发某些操作。我的想法如下:

  1. 保留对在InfoWindowAdapter中创建的自定义infoWindow的引用。
  2. MapFragment(或MapView)包装在自定义ViewGroup中(我的名称称为MapWrapperLayout)
  3. 覆盖MapWrapperLayout的dispatchTouchEvent,(如果当前显示的是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的任何UI更改。为此,您必须手动调用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)上进行了测试,如果有机会,我会在一些姜饼手机上进行尝试。到目前为止,我发现的一个局限性是您不能从屏幕上的按钮拖动地图到处移动。也许可以通过某种方式克服它,但就目前而言,我可以接受。

我知道这是一个丑陋的破解,但是我发现并没有发现更好的东西,而且我非常需要这种设计模式,这真的是回到map v1框架的理由(顺便说一句。我真的很想避免包含片段的新应用等)。我只是不明白为什么Google不向开发人员提供某种正式的方法来在InfoWindows上提供按钮。这是一种常见的设计模式,而且即使在正式的Google Maps应用程序中也使用此模式:)。我了解他们不能在InfoWindows中仅使视图“实时”的原因-这可能会在移动和滚动地图时降低性能。但是应该有一些方法可以在不使用视图的情况下实现这种效果。


6
有趣的解决方案。我想尝试一下。表现如何?
帕特里克

10
需要替换view.setBackground(bgDrawablePressed);if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { view.setBackgroundDrawable(bgDrawablePressed); }else{ view.setBackground(bgDrawablePressed); }才能在Android Gingerbread中工作,请注意:view.setBackground代码中还会再出现一次。
Balaji 2013年

4
KK_07k11A0585:看来您的InfoWindowAdapter实现可能是错误的。有两种方法可以覆盖:getInfoWindow()和getInfoContents()。框架首先调用getInfoWindow()方法,并且(仅)如果它返回null,则调用getInfoContents()。如果从getInfoWindow返回某些View,则框架会将其放置在默认信息窗口框架内-在您的情况下,您不希望这样做。因此,只需从getInfoWindow返回null并从getInfoContent返回View,就可以了。
13年

18
如果有人感兴趣,我将在自己的应用程序CG Transit(您可以在Google Play上找到它)中使用此解决方案。两个月后,它已被成千上万的用户使用,但尚未有人抱怨它。
007

2
如果不使用标准的信息窗口,如何确定底部偏移量?
Rarw 2014年

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/


这将减慢/滞后滚动地图
Shane Ekanayake 2015年

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

编辑:这是我一步一步做的方式

首先,在您的活动/片段中的某处填充您自己的信息窗口(全局变量)。我的是碎片。还请确保您的信息窗口布局中的根视图是linearlayout(由于某些原因,relativelayout占用了信息窗口中整个屏幕的宽度)

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是Maps> Documentation-Getting Started,请遵循此步骤)

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

你能告诉我你的代码吗?我能够成功记录触摸事件,但无法记录点击事件,因此我进行了此实现。另外,您需要正确实施choice007的解决方案。
Manish Jangid

我分享了完整的实施过程。让我知道您是否有任何疑问
Manish Jangid '16

0

只是一种推测,我没有足够的经验来尝试...)-:

由于GoogleMap是片段,因此应该可以捕获标记onClick事件并显示自定义片段视图。地图片段仍将在背景上可见。有人尝试过吗?任何原因为什么它不起作用?

缺点是地图片段将在backgroud上冻结,直到自定义信息片段将控件返回给它为止。


5
我认为发布猜测作为答案并不有趣。也许应该是对原始问题的评论。只是我的想法。
Johan Karlsson 2015年


-2

我已经为这个问题构建了一个示例android studio项目。

输出屏幕截图:-

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

下载完整的项目源代码,请单击 此处

请注意:您必须在Androidmanifest.xml中添加API密钥


5
最好通过Github / gist而不是zip文件共享代码。这样我们就可以在那里直接检查。
Noundla Sandeep'2

我发现一个小错误,当您按某个按钮时,所有按钮都被单击。
Morozov

3
@Noundla和其他人:不要麻烦下载他的压缩代码。这是此问题已接受答案的精确副本。
Ganesh Mohan

1
@ ganesh2shiv是正确的,压缩后的代码没有用。您不应该附上复制粘贴的代码
Onkar宁宁

-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是我们的自定义布局,用于显示将取代信息窗口的视图。我只是在这里添加了textview。您可以在此处添加附加视图,使其类似于示例捕捉。我的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

刚刚尝试了一下,它的作用就像膨胀其他任何xml布局一样-很好
Rarw

31
看来您没有阅读我的问题。我知道如何在infowindow中创建自定义视图。我不知道的是如何在其中制作自定义按钮并收听其单击事件。
user1943012 2013年

5
此解决方案无法回答原始问题
biddulph.r 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.