欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > 内容正文

android 地图开发之聚合,定位,android聚合

来源: 开发者 投稿于  被查看 39253 次 评论:140

android 地图开发之聚合,定位,android聚合


这次的demo以高德为例做的地图聚合。相信你们只要懂了原理,其他的地图三方都可以做到。

聚合大概意思就是当地图缩小到里面的marker差不多快重叠的时候,让2个marker变成1个marker。口说无凭,下面看效果图就明白是何意思。
这里写图片描述

首先我们理清思路:
1、我们需要一个装有所有数据的集合,和一个只有当前界面才能看到的数据集合。当然我们肯定只会显示当前界面看到的所以marker。所以这里我们需要监听地图改变时的监听,但我们不可能在改变的过程当中来进行筛选和刷新这样就太浪费资源,所以当地图改变完之后的监听进行这样的操作;
2、我们需要一个自定义的marker来遍历当前界面所看到的所有marker集合。来进行一个聚合。每个marker只能合并一次。所以说假如地图上有3个点,一个点和另一个点聚合了之后就不能在与第三个点聚合了。
3、通过上面的操作我们就可以拿到可见范围内的所有marker集合。那现在就是要把所有marker定在地图上面,通过坐标点。聚合点的位置就是所有聚合marker的位置的中心点。
4、地图上的聚合功能不能有旋转功能,所以我把3d地图的旋转给禁了。

好,下面我们开始贴代码,代码里面的注释很详细。如有疑问可以留言。

首先是调用mapview的主类

package com.wyw.amap;

import java.util.ArrayList;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.location.LocationManagerProxy;
import com.amap.api.location.LocationProviderProxy;
import com.amap.api.maps.AMap;
import com.amap.api.maps.AMap.OnCameraChangeListener;
import com.amap.api.maps.AMap.OnMarkerClickListener;
import com.amap.api.maps.AMapOptions;
import com.amap.api.maps.CameraUpdateFactory;
import com.amap.api.maps.MapView;
import com.amap.api.maps.Projection;
import com.amap.api.maps.UiSettings;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.CameraPosition;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;

import android.app.Activity;
import android.graphics.Point;
import android.location.Location;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;

public class MainActivity extends Activity implements OnCameraChangeListener,
        OnMarkerClickListener, AMapLocationListener {
    /**
     * 地图view
     */
    private MapView mapView;
    /**
     * 高德amap
     */
    private AMap aMap;
    /**
     * 定位
     */
    private LocationManagerProxy aMapLocManager = null;
    /**
     * 所有的marker
     */
    private ArrayList<MarkerOptions> markerOptionsListall = new ArrayList<MarkerOptions>();
    /**
     * 视野内的marker
     */
    private ArrayList<MarkerOptions> markerOptionsListInView = new ArrayList<MarkerOptions>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mapView = (MapView) findViewById(R.id.map);
        //因为现在屏幕比较大单手不方便操作,高德我没找到能把 定位自己的按钮放在右下角的方法,所以就模拟一个
        findViewById(R.id.nearby_linear_img_location_bottom_right).setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // 先销毁定位
                if (aMapLocManager != null) {
                    aMapLocManager.removeUpdates(MainActivity.this);
                    aMapLocManager.destory();
                }
                aMapLocManager = null;
                //再重启定位
                if (aMapLocManager == null) {
                    aMapLocManager = LocationManagerProxy.getInstance(MainActivity.this);
                    /*
                     * mAMapLocManager.setGpsEnable( false);
                     * 1.0.2版本新增方法,设置true表示混合定位中包含gps定位 ,
                     * false表示纯网络定位,默认是true Location
                     * API定位采用GPS和网络混合定位方式 ,
                     * 第一个参数是定位provider,第二个参数时间最短是2000毫秒
                     * ,第三个参数距离间隔单位是米,第四个参数是定位监听者
                     */
                    aMapLocManager.requestLocationUpdates(LocationProviderProxy.AMapNetwork, 2000,10, MainActivity.this);
                }
            }
        });

        //方法必须重写
        mapView.onCreate(savedInstanceState);

        if (aMapLocManager == null) {
            //打开定位
            aMapLocManager = LocationManagerProxy
                    .getInstance(MainActivity.this);
            /**
             * mAMapLocManager.setGpsEnable(false);//
             * 1.0.2版本新增方法,设置true表示混合定位中包含gps定位,false表示纯网络定位,默认是true Location
             * API定位采用GPS和网络混合定位方式 ,第一个参数是定位provider,第二个参数时间最短是2000毫秒
             * ,第三个参数距离间隔单位是米,第四个参数是定位监听者
             */
            aMapLocManager.requestLocationData(
                    LocationProviderProxy.AMapNetwork, 2000, 10,
                    MainActivity.this);

        }

        if (aMap == null) {
            aMap = mapView.getMap();
            UiSettings mUiSettings = aMap.getUiSettings();//拿到地图工具类
            mUiSettings.setTiltGesturesEnabled(false);// 禁用倾斜手势。
            mUiSettings.setRotateGesturesEnabled(false);// 禁用旋转手势。
            mUiSettings.setZoomPosition(AMapOptions.ZOOM_POSITION_RIGHT_CENTER);//放大缩小按钮放在屏幕中间

            aMap.setOnMarkerClickListener(this);// 设置点击marker事件监听器
            aMap.setOnCameraChangeListener(this);// 对amap添加移动地图事件监听器
        }
        //添加临时数据
        addDate();
    }

    // 添加临时数据
    private void addDate() {
        for (int i = 0; i < 200; i++) {
            LatLng latLng = new LatLng(Math.random() * 6 + 22,
                    Math.random() * 6 + 113);
            markerOptionsListall.add(new MarkerOptions()
                    .position(latLng)
                    .title("Marker" + i)
                    .icon(BitmapDescriptorFactory
                            .defaultMarker(BitmapDescriptorFactory.HUE_BLUE)));
        }
    }

    @Override
    public boolean onMarkerClick(Marker arg0) {
        // TODO marker点击监听
        return false;
    }

    @Override
    public void onCameraChange(CameraPosition arg0) {
        // TODO 地图改变时的监听

    }

    @Override
    public void onCameraChangeFinish(CameraPosition arg0) {// 地图改变完之后的监听
        resetMarks();
    }

     /**
     * 方法必须重写
     */
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        mapView.onSaveInstanceState(outState);
    }
    /**
     * 方法必须重写
     */
    @Override
    protected void onResume() {
        super.onResume();
        mapView.onResume();
    }
    /**
     * 方法必须重写
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mapView.onDestroy();

        if (aMapLocManager != null) {
            aMapLocManager.removeUpdates(this);
            aMapLocManager.destroy();
        }
        aMapLocManager = null;
    }

    /**
     * 方法必须重写
     */
    @Override
    protected void onPause() {
        super.onPause();
        mapView.onPause();

        if (aMapLocManager != null) {
            aMapLocManager.removeUpdates(this);
            aMapLocManager.destroy();
        }
        aMapLocManager = null;
    }

    /**
     * 获取视野内的marker 根据聚合算法合成自定义的marker 显示视野内的marker
     */
    private void resetMarks() {
        // 开始刷新
        Projection projection = aMap.getProjection();
        Point p = null;
        markerOptionsListInView.clear();
        // 获取在当前视野内的marker;提高效率
        for (MarkerOptions mp : markerOptionsListall) {
            p = projection.toScreenLocation(mp.getPosition());
            if (p.x < 0 || p.y < 0|| p.x > getResources().getDisplayMetrics().widthPixels|| p.y > getResources().getDisplayMetrics().heightPixels) {
                // 不添加到计算的列表中
            } else {
                //在当前可观区域内
                markerOptionsListInView.add(mp);
            }
        }
        // 自定义的聚合类MyMarkerCluster
        ArrayList<MyGaodeImageView> clustersMarker = new ArrayList<MyGaodeImageView>();
        for (MarkerOptions mp : markerOptionsListInView) {
            if (clustersMarker.size() == 0) {
                //添加一个新的自定义marker
                clustersMarker.add(new MyGaodeImageView(MainActivity.this, mp,
                        projection, 80));//80=相距多少才聚合
            } else {
                boolean isIn = false;
                for (MyGaodeImageView cluster : clustersMarker) {
                    //判断当前的marker是否在前面marker的聚合范围内 并且每个marker只会聚合一次。
                    if (cluster.getBounds().contains(mp.getPosition())) {
                        cluster.addMarker(mp);
                        isIn = true;
                        break;
                    }
                }
                //如果没在任何范围内,自己单独形成一个自定义marker。在和后面的marker进行比较
                if (!isIn) {
                    clustersMarker.add(new MyGaodeImageView(MainActivity.this,mp, projection, 80));//80=相距多少才聚合
                }
            }
        }
        // 设置聚合点的位置和icon
        for (MyGaodeImageView mmc : clustersMarker) {
            mmc.setpositionAndIcon();
        }
        aMap.clear();
        // 重新添加 marker
        for (MyGaodeImageView cluster : clustersMarker) {
            aMap.addMarker(cluster.getOptions());
        }
    }

    @Override
    public void onLocationChanged(Location location) {
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
    }

    @Override
    public void onLocationChanged(AMapLocation location) {// 高德地图上面4个方法都废弃了。
        if (location != null) {
            aMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(
                    location.getLatitude(), location.getLongitude()), 8));

            // 定位成功  销毁定位
            if (aMapLocManager != null) {
                aMapLocManager.removeUpdates(MainActivity.this);
                aMapLocManager.destory();
            }
            aMapLocManager = null;
        }

    }
}

再来就是一个自定义marker辅助类了

package com.wyw.amap;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.MeasureSpec;
import android.widget.ImageView;
import android.widget.TextView;

import com.amap.api.maps.Projection;
import com.amap.api.maps.model.BitmapDescriptorFactory;
import com.amap.api.maps.model.LatLng;
import com.amap.api.maps.model.LatLngBounds;
import com.amap.api.maps.model.MarkerOptions;

import java.util.ArrayList;

public class MyGaodeImageView {
    //上下文
    private Context context;
    //marker类
    private MarkerOptions options;
    //当前可观区域里的 聚合过之后的集合
    private ArrayList<MarkerOptions> includeMarkers;
    // 创建区域
    private LatLngBounds bounds;

    /**
     * 头像加载完监听
     */
    public MyGaodeImageView(Context context, MarkerOptions firstMarkers,
            Projection projection, int gridSize) {
        this.context = context;
        options = new MarkerOptions();

        Point point = projection.toScreenLocation(firstMarkers.getPosition());
        //范围类
        Point southwestPoint = new Point(point.x - gridSize, point.y + gridSize);
        //范围类
        Point northeastPoint = new Point(point.x + gridSize, point.y - gridSize);

        bounds = new LatLngBounds(projection.fromScreenLocation(southwestPoint),
                projection.fromScreenLocation(northeastPoint));
        //设置初始化marker属性
        options.anchor(0.5f, 0.5f).title(firstMarkers.getTitle()).position(firstMarkers.getPosition())
                .icon(firstMarkers.getIcon())
                .snippet(firstMarkers.getSnippet());
        includeMarkers = new ArrayList<MarkerOptions>();
        includeMarkers.add(firstMarkers);
    }

    public MyGaodeImageView(Context context) {
        this.context = context;
    }

    public LatLngBounds getBounds() {
        return bounds;
    }

    public MarkerOptions getOptions() {
        return options;
    }

    public void setOptions(MarkerOptions options) {
        this.options = options;
    }

    /**
     * 添加marker
     */
    public void addMarker(MarkerOptions markerOptions) {
        includeMarkers.add(markerOptions);// 添加到列表中
    }

    /**
     * 设置聚合点的中心位置以及图标
     */
    public void setpositionAndIcon() {
        int size = includeMarkers.size();
        double lat = 0.0;
        double lng = 0.0;
        // 一个的时候
        if (size == 1) {//设置marker单个属性
            // 设置marker位置
            options.position(new LatLng(
                    includeMarkers.get(0).getPosition().latitude,
                    includeMarkers.get(0).getPosition().longitude));
            options.title("聚合点");
            options.icon(BitmapDescriptorFactory
                    .fromBitmap(getViewBitmap(getView(size))));

        } else {// 聚合的时候
            //设置marker聚合属性
            for (MarkerOptions op : includeMarkers) {
                lat += op.getPosition().latitude;
                lng += op.getPosition().longitude;
            }
            // 设置marker的位置为中心位置为聚集点的平均位置
            options.position(new LatLng(lat / size, lng / size));
            options.title("聚合点");
            options.icon(BitmapDescriptorFactory
                    .fromBitmap(getViewBitmap(getView(size))));
        }
    }

    /**
     * marker试图
     */
    public View getView(int num) {
        View view = LayoutInflater.from(context).inflate(
                R.layout.view_gaode_img, null);
        /** 数量 */
        TextView txt_num = (TextView) view
                .findViewById(R.id.view_gaode_txt_num);
        /** 头像 */
        ImageView img_portrait = (ImageView) view
                .findViewById(R.id.view_gaode_img_portrait);

        img_portrait.setPadding(8, 0, 8, 12);
        if (num > 1) {
            txt_num.setText(num + "");
            txt_num.setGravity(Gravity.CENTER);
            txt_num.setVisibility(View.VISIBLE);
        } else {
            txt_num.setVisibility(View.GONE);
            img_portrait.setBackgroundResource(R.drawable.location_marker_man);
        }
        return view;
    }

    /**
     * 把一个view转化成bitmap对象
     */
    public static Bitmap getViewBitmap(View view) {
        Bitmap bitmap = null;
        try {
            if (view != null) {
                view.measure(
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                view.layout(0, 0, view.getMeasuredWidth(),
                        view.getMeasuredHeight());
                view.buildDrawingCache();
                bitmap = view.getDrawingCache();
            }
        } catch (Exception e) {
        }

        return bitmap;
    }
}

还有就是请注意,想成功运行出来需要自己去 高德开放平台去申请地图key。在AndroidManifest.xml 换成自己的key就可以了。

<!-- android:value="自己申请的key" -->
<meta-data
            android:name="com.amap.api.v2.apikey"
            android:value="f340b023108fc22e6e3b90af0c8ee3c9"/>

其他XML文件我就不贴出来了。如果想继续研究本demo可去下面的地址下载。

最后就是:
希望大家多多关注我的博客,多多支持我。
如有好意见或更好的方式欢迎留言谈论。

下面是地址传送门:
http://download.csdn.net/detail/u013895206/9093471

转载请注明:(http://blog.csdn.net/u013895206) !

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关频道:

用户评论