Android高德地图之多InfoWindow

本文是高德地图系列的最后一文,因为光是写这几篇博文,就花去了我一整天时间,什么也没做,甚至饭也没吃,做了一整天,现在身体已经空荡荡了,而且最近一段时间工作很忙,每天都很累,所以打算多去锻炼身体。有任何疑问也可以留言。


最终效果:生成marker并显示详情
这里写图片描述

由于不能上传2M以上的截图,只录了重点,废话不多讲,速度上车。

Marker表示为地图上的一个点,一个Point,我们可以在这个Marker做各种各样的操作包括,拖动,获取地理坐标,反编译地址等等。现在,我们要将Marker添加到地图上,并达到图上的效果。

在官方论坛上看到很多人不知道如何实现多InfoWindow的方法,基于此,我决定写一篇关于实现多Infowindow的曲线救国的方式,按照我这篇文章,我相信你也能做出这种效果。

ok以我的项目为例,需求是在地图显示一种设备的详情,可以看到设备ID,类型,次数,经纬度,反地理位置,时间,电量等等。下面是我的实体类BeanEvent 。

private Integer id;
    private String deviceId;
    private String simId;
    private String eventId;
    private String eventType;
    private String eventCount;
    private String latitude;
    private String longitude;
    private String eventTime;
    private String actTime;
    private String battery;
    private String eventIp;
    ---此处省略get set方法
    // 假数据
    public static List<BeanEvent> getEvent()
    {
        List<BeanEvent> list = new ArrayList<>();
        BeanEvent be1 = new BeanEvent();
        be1.setDeviceId("devid--1111111");
        be1.setSimId("simid--1111111");
        be1.setEventId("event_1111111");
        be1.setEventType("type-1111111");
        be1.setEventCount("count_1111111");
        be1.setLatitude("39.92746");
        be1.setLongitude("116.396481");
        be1.setEventTime("20170911");
        be1.setBattery("1111111");
        be1.setEventIp("1111111");
        BeanEvent be2 = new BeanEvent();
        be2.setDeviceId("devid--222222");
        be2.setSimId("simid--22222");
        be2.setEventId("event_22222");
        be2.setEventType("type-22222");
        be2.setEventCount("count_22222");
        be2.setLatitude("39.93746");
        be2.setLongitude("116.398681");
        be2.setEventTime("20170911");
        be2.setBattery("1111111");
        be2.setEventIp("1111111");
        BeanEvent be3 = new BeanEvent();
        be3.setDeviceId("devid--33333");
        be3.setSimId("simid--3333");
        be3.setEventId("event_33333");
        be3.setEventType("type-33333");
        be3.setEventCount("count_33333");
        be3.setLatitude("39.92956");
        be3.setLongitude("116.399541");
        be3.setEventTime("20170911");
        be3.setBattery("1111111");
        be3.setEventIp("1111111");
        list.add(be1);
        list.add(be2);
        list.add(be3);
        return list;
    }

至此,数据源被模拟出来了。
官方的添加marker的方法

	/**
	 * 在地图上添加marker
	 */
	private void addMarkersToMap() {
		markerOption = new MarkerOptions().icon(BitmapDescriptorFactory
				.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
				.position(latlng)
				.title("标题")
				.snippet("详细信息")
				.draggable(true);
		marker = aMap.addMarker(markerOption);
		marker.showInfoWindow();
	}

添加InfoWindow的代码我就不演示了,太浪费大家时间,我会直接告诉你,官方代码里的Marker的InfoWindow不支持多个同时显示,当设置了多个Marker的Infowindow时,只显示最后一个,这时该怎么办呢?

看看我是如何将他们显示出来的

 ***初始化。。。
 addMarkersToMap(getEvent()); // 添加点
/**
     * 在地图上添加marker
     */
    private void addMarkersToMap(List<BeanEvent> eventList)
    {
        for (int i = 0; i < eventList.size(); i++)
        {
            BeanEvent be = eventList.get(i);
            markerOption = new MarkerOptions().icon(BitmapDescriptorFactory
                    .fromView(getBitmapView(mActivity, be))).draggable(false);
            markerOption.position(new LatLng(Double.parseDouble(be.getLatitude()), Double.parseDouble(be.getLongitude())));
            marker = aMap.addMarker(markerOption);
            marker.setObject(be);
            markerList.add(marker);
        }
    }

其中,BitmapDescriptorFactory
.fromView(getBitmapView(mActivity, be))方法将返回一个View对象作为Marker的Icon,因此,这里,我们可以借助这个方法,实现将Marker与Infowindow结合在一起,即,看起来是marker和Infowindow,实际上,它们整体就是一个Marker。因为marker是多支持多个显示的,所以这样的思路是没有问题的。

其方法是这样写的:


    public static View getBitmapView(Context context, BeanEvent be)
    {
        LayoutInflater factory = LayoutInflater.from(context);
        View view = factory.inflate(R.layout.item_marker_title, null);
        TextView tv_title = (TextView) view.findViewById(R.id.tv_title);
        TextView tv_snippet = (TextView) view.findViewById(R.id.tv_snippet);
        tv_title.setText("SIM卡号:" + be.getSimId());
        tv_snippet.setText("公章ID:" + be.getDeviceId());
        return view;
    }

该方法将传入的对象赋在对应的控件上,然后作为View返回。此时的预览图为
这里写图片描述
上图就是我们最终作为marker的icon的图,届时,只需要传入虚拟数据或真实数据,即可显示出来。

此时多个InfoWindow就实现了。接下来,我们将实现点击marker弹出详情。

我们先来看一下布局结构:

<RelativeLayout
                android:id="@+id/rl_info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_margin="2dp"
                android:animateLayoutChanges="true"
                android:background="@drawable/bg_seal_info"
                android:clickable="true"
                android:focusable="true"
                android:focusableInTouchMode="true"
                android:orientation="vertical"
                android:showDividers="middle"
                android:visibility="gone"
                app:divider="@drawable/iv_devider">

                <TextView
                    android:id="@+id/tv_close"
                    android:layout_width="40dp"
                    android:layout_height="40dp"
                    android:layout_alignParentRight="true"
                    android:background="@mipmap/ic_seal"/>

                <LinearLayout
                    android:id="@+id/ll_1"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="10dp">

                    <TextView
                        android:id="@+id/tv_sim"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="卡号:"
                        android:textSize="14sp"/>

                    <TextView
                        android:id="@+id/tv_count"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="次数:"
                        android:textSize="14sp"/>
                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_2"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/ll_1"
                    android:orientation="horizontal"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="5dp">

                    <TextView
                        android:id="@+id/tv_sealNo"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="公章号:"
                        android:textSize="14sp"/>

                    <TextView
                        android:id="@+id/tv_type"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="事件类型:"
                        android:textSize="14sp"/>
                </LinearLayout>

                <LinearLayout
                    android:id="@+id/ll_3"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/ll_2"
                    android:orientation="horizontal"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="5dp">

                    <TextView
                        android:id="@+id/tv_latitude"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="北纬:"
                        android:textSize="14sp"/>

                    <TextView
                        android:id="@+id/tv_longitude"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="东经:"
                        android:textSize="14sp"/>
                </LinearLayout>

                <TextView
                    android:id="@+id/tv_address"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/ll_3"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="5dp"
                    android:text="地址:"
                    android:textSize="14sp"/>

                <LinearLayout
                    android:id="@+id/ll_4"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/tv_address"
                    android:orientation="horizontal"
                    android:paddingBottom="10dp"
                    android:paddingLeft="10dp"
                    android:paddingRight="10dp"
                    android:paddingTop="5dp">

                    <TextView
                        android:id="@+id/tv_battery"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="电量:"
                        android:textSize="14sp"/>

                    <TextView
                        android:id="@+id/tv_ip"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_weight="1"
                        android:text="IP:"
                        android:textSize="14sp"/>
                </LinearLayout>

            </RelativeLayout>

效果为:

这里写代码片

由于详情中,用到了反地理编译,即已知经纬度获取地理位置。
所以我们在Activity中实现以下几个接口:

 implements GeocodeSearch.OnGeocodeSearchListener, AMap.OnMarkerClickListener

同时,将刚刚的布局隐藏掉,作为一个适配器使用:

    public void setInfo(final RelativeLayout rl_layout, Marker marker, RegeocodeResult result)
    {
        ViewHolder viewHolder = null;
        if (rl_layout.getTag() == null)
        {
            viewHolder = new ViewHolder();
            viewHolder.tv_close = (TextView) rl_layout.findViewById(R.id.tv_close);
            viewHolder.tv_sim = (TextView) rl_layout.findViewById(R.id.tv_sim);
            viewHolder.tv_count = (TextView) rl_layout.findViewById(R.id.tv_count);
            viewHolder.tv_sealNo = (TextView) rl_layout.findViewById(R.id.tv_sealNo);
            viewHolder.tv_address = (TextView) rl_layout.findViewById(R.id.tv_address);
            viewHolder.tv_latitude = (TextView) rl_layout.findViewById(R.id.tv_latitude);
            viewHolder.tv_longitude = (TextView) rl_layout.findViewById(R.id.tv_longitude);
            viewHolder.tv_battery = (TextView) rl_layout.findViewById(R.id.tv_battery);
            viewHolder.tv_type = (TextView) rl_layout.findViewById(R.id.tv_type);
            viewHolder.tv_ip = (TextView) rl_layout.findViewById(R.id.tv_ip);
            rl_layout.setTag(viewHolder);
        }
        viewHolder = (ViewHolder) rl_layout.getTag();
        BeanEvent be = (BeanEvent) marker.getObject();
        viewHolder.tv_sim.setText("SIM::" + be.getSimId());
        viewHolder.tv_count.setText("次数:" + be.getEventCount());
        viewHolder.tv_sealNo.setText("公章号:" + be.getDeviceId());
        viewHolder.tv_address.setText(result == null || result.getRegeocodeAddress() == null
                || result.getRegeocodeAddress().getFormatAddress() == null ? "地址:对不起,没有找到相关地理位置!" : "地址:" + result.getRegeocodeAddress().getFormatAddress() + "附近");
        viewHolder.tv_type.setText("类型:" + be.getEventType());
        viewHolder.tv_latitude.setText("东经:" + be.getLatitude());
        viewHolder.tv_longitude.setText("北纬:" + be.getLongitude());
        viewHolder.tv_battery.setText("电量:" + be.getBattery());
        viewHolder.tv_ip.setText("IP:" + be.getEventIp());

        final ViewHolder finalViewHolder = viewHolder;
        viewHolder.tv_close.setOnClickListener(v ->
        {
            rl_layout.startAnimation(AnimUtils.goneAnim());
            rl_layout.setVisibility(View.GONE);
        });
    }

    class ViewHolder
    {
        TextView tv_address, tv_close, tv_sim, tv_count, tv_sealNo, tv_type, tv_latitude, tv_longitude, tv_battery, tv_ip;
    }

最后,当我们点击,marker的时候,将布局显示出来,此处要实现marker的onclicklistener方法:

animMove(aMap, marker.getPosition()); // 带动画的移动地图到marker
        MainActivity.instant.showToast("正在获取地址信息...");
        // 发起地理编码请求
        if (rl_info.getVisibility() == View.VISIBLE) // 如果当前已经有详情在显示,先Gone掉
        {
            rl_info.startAnimation(AnimUtils.goneAnim());
            rl_info.setVisibility(View.GONE);
        }
        RegeocodeQuery query = new RegeocodeQuery(convertToLatLonPoint(marker.getPosition()), 200, GeocodeSearch.AMAP);
        geoSearch.getFromLocationAsyn(query);// 设置异步逆地理编码请求
        return false;

接下来,在实现地理位置的实现方法:

    @Override
    public void onRegeocodeSearched(RegeocodeResult result, int i)
    {
        if (i == AMapException.CODE_AMAP_SUCCESS)
        {
            setInfo(rl_info, marker, result); // 将结果显示在marker对应的详情布局上
            rl_info.startAnimation(AnimUtils.showAnim());
            rl_info.setVisibility(View.VISIBLE); // 显示
        } else MainActivity.instant.showToast("获取地址失败!请稍后重试!");
    }

    @Override
    public void onGeocodeSearched(GeocodeResult geocodeResult, int i)
    {

    }

这样,我们就实现了图上的效果。
最后贴出MapUtils:

 /**
     * 把LatLng对象转化为LatLonPoint对象
     */
    public static LatLonPoint convertToLatLonPoint(LatLng latlon)
    {
        return new LatLonPoint(latlon.latitude, latlon.longitude);
    }

    /**
     * 把LatLonPoint对象转化为LatLon对象
     */
    public static LatLng convertToLatLng(LatLonPoint latLonPoint)
    {
        return new LatLng(latLonPoint.getLatitude(), latLonPoint.getLongitude());
    }
/**********************************************************移动地图**************************************/
	public static void animMove(AMap aMap, LatLng latLng)
    {
        aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15));
    }

    public static void animMove(AMap aMap, LatLonPoint point)
    {
        aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(convertToLatLng(point), 15));
    }

    public static void animMove(AMap aMap, AMapLocation location)
    {

        aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 18));
    }

至此,该功能已经完全实现。


  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值