27
2017
09

Android百度地图点聚合开发

Android百度地图点聚合开发

自v3.3.0版本起,SDK提供了给Marker增加动画的能力,具体实现方法如下:// 通过marker的icons设置一组图片,再通过period设置多少帧刷新一次图片资源这是官方的介绍,下面看看具体实现方法。

代码结构

主要包括java,manifest,drawable,layout
如图:
这里写图片描述
首先java包括MainActivity,MyApplication等等。
第一个类是Cluster代码如下:

public class Cluster {

    private static final String TAG = "Cluster";
    private static final String TAG_ADD_Cluster = "AddCluster_method";
    private Context mContext;
    private MapView mMapView;
    private Boolean isAverageCenter;
    private int mGridSize;
    private double mDistance;

    private List<ClusterMarker> mClusterMarkers;


    public Cluster(Context context, MapView mapView
            , Boolean isAverageCenter
            , int mGridSize, double mDistance) {
        this.mContext = context;
        this.mMapView = mapView;
        this.isAverageCenter = isAverageCenter;
        this.mGridSize = mGridSize;
        this.mDistance = mDistance;
        mClusterMarkers = new ArrayList<>();
    }

    public ArrayList<MarkerOptions> createCluster(List<MarkerOptions> markerList) {
        this.mClusterMarkers.clear();
        ArrayList<MarkerOptions> itemList = new ArrayList<MarkerOptions>();
        for (int i = 0; i < markerList.size(); i++) {
            addCluster(markerList.get(i));
        }
        for (int i = 0; i < mClusterMarkers.size(); i++) {
            ClusterMarker cm = mClusterMarkers.get(i);
            setClusterDrawable(cm);
            MarkerOptions oi = new MarkerOptions().position(cm.getmCenter()).icon(cm.getMarkerOptions().getIcon());
            itemList.add(oi);
        }

        Log.e(TAG, "itemList.size:" + itemList.size());
        return itemList;
    }

    /** * 添加标注点,如果第一次添加,直接新建,否则与地图上原有的点进行判断,如果距离小于mDistance,则进行聚合 * * @param marker */

    private void addCluster(MarkerOptions marker) {
        LatLng markGeo = marker.getPosition();
        // 没有ClusterMarkers
        if (mClusterMarkers.size() == 0) {
            ClusterMarker clusterMarker = new ClusterMarker(marker.getPosition());
            clusterMarker.getMarkerOptions().icon(marker.getIcon());
            clusterMarker.AddMarker(marker, isAverageCenter);
            MBound bound = new MBound(markGeo.latitude, markGeo.longitude, markGeo.latitude, markGeo.longitude);
            bound = MapUtils.getExtendedBounds(mMapView, bound, mGridSize);
            clusterMarker.setmGridBounds(bound);
            mClusterMarkers.add(clusterMarker);
        } else {
            ClusterMarker clusterContain = null;
            double distance = mDistance;

            for (int i = 0; i < mClusterMarkers.size(); i++) {
                ClusterMarker clusterMarker = mClusterMarkers.get(i);
                Log.e(TAG_ADD_Cluster, "in mClusterMarker.size size = = " + mClusterMarkers.size());
                LatLng center = clusterMarker.getmCenter();
                double d = DistanceUtil.getDistance(center, marker.getPosition());

                //[]--------选择clusterMarker 中最近的,clusterMarker-------双重循环-----------[]
                if (d < distance) {
                    distance = d;
                    clusterContain = clusterMarker;
                } else {
// Log.d(TAG_ADD_Cluster, "d>distence,不满足聚合距离");
                }

            }

            // 现存的clusterMarker 没有符合条件的
            if (clusterContain == null || !isMarkersInCluster(markGeo, clusterContain.getmGridBounds())) {
// Log.e(TAG_ADD_Cluster, "======clusterContain=======================--------------");
                ClusterMarker clusterMarker = new ClusterMarker(marker.getPosition());

                clusterMarker.getMarkerOptions().icon(marker.getIcon());
                clusterMarker.AddMarker(marker, isAverageCenter);
                MBound bound = new MBound(markGeo.latitude, markGeo.longitude, markGeo.latitude, markGeo.longitude);
                bound = MapUtils.getExtendedBounds(mMapView, bound, mGridSize);
                clusterMarker.setmGridBounds(bound);

                mClusterMarkers.add(clusterMarker);

            } else {
                clusterContain.AddMarker(marker, isAverageCenter);
                Log.e(TAG_ADD_Cluster, "添加到选中 clusterMarker:--->clusterContain.size:---->" + clusterContain.getmMarkers().size());
            }
        }
    }

    /** * 设置聚合点的颜色与中间数字 * * @param clusterMarker */
    private void setClusterDrawable(ClusterMarker clusterMarker) {

        View drawableView = LayoutInflater.from(mContext).inflate(
                R.layout.drawable_mark, null);
        TextView text = (TextView) drawableView.findViewById(R.id.drawble_mark);
        text.setPadding(3, 3, 3, 3);

        int markNum = clusterMarker.getmMarkers().size();
        Log.e("setClusterDrawable", "!!!!!!!!!!!!!!!!!!!!!!!" + markNum);
        if (markNum >= 2) {
            text.setText(markNum + "");
            if (markNum < 11) {
                text.setBackgroundResource(R.drawable.m0);
            } else if (markNum > 10 && markNum < 21) {
                text.setBackgroundResource(R.drawable.m1);
            } else if (markNum > 20 && markNum < 31) {
                text.setBackgroundResource(R.drawable.m2);
            } else if (markNum > 30 && markNum < 41) {
                text.setBackgroundResource(R.drawable.m3);
            } else {
                text.setBackgroundResource(R.drawable.m4);
            }
            clusterMarker.getMarkerOptions().icon(BitmapDescriptorFactory.fromView(drawableView));
        } else {

            clusterMarker.getMarkerOptions().icon(BitmapDescriptorFactory.fromResource(R.drawable.nav_turn_via_1));
        }
    }

    /** * 判断坐标点是否在MBound 覆盖区域内 * * @param markerGeo * @param bound * @return */
    private Boolean isMarkersInCluster(LatLng markerGeo, MBound bound) {

        Log.e(TAG, "rightTopLat:" + bound.getRightTopLat());
        Log.e(TAG, "rightTopLng:" + bound.getRightTopLng());
        Log.e(TAG, "leftBottomLat:" + bound.getLeftBottomLat());
        Log.e(TAG, "leftBottomlng:" + bound.getLeftBottomLng());

        if (markerGeo.latitude > bound.getLeftBottomLat()
                && markerGeo.latitude < bound.getRightTopLat()
                && markerGeo.longitude > bound.getLeftBottomLng()
                && markerGeo.longitude < bound.getRightTopLng()) {
            return true;
        }
        return false;

    }

}

接着是ClusterMarker类:

public class ClusterMarker {
    private LatLng mCenter;
    private List<MarkerOptions> mMarkers;
    private MBound mGridBounds;

    public MarkerOptions getMarkerOptions() {
        return mMarkerOptions;
    }

    private MarkerOptions mMarkerOptions;

    public ClusterMarker(LatLng geoPoint) {
        mMarkers = new ArrayList<>();
        mMarkerOptions = new MarkerOptions().position(geoPoint);
    }

    /** * 计算平均中心点 * * @return */
    private LatLng calAverageCenter() {
        double latitude = 0, longitude = 0;
        int len = mMarkers.size() == 0 ? 1 : mMarkers.size();

        Log.e("calAverageCenter:", "calAverageCenter:------>" + len);

        for (int i = 0; i < len; i++) {
            latitude = latitude + mMarkers.get(i).getPosition().latitude;
            longitude = longitude + mMarkers.get(i).getPosition().longitude;
        }

        return new LatLng((int) (latitude / len), (int) (longitude / len));
    }

    /** * ClusterMarker 中添加marker * * @param marker * @param isAverageCenter */
    public void AddMarker(MarkerOptions marker, Boolean isAverageCenter) {
        mMarkers.add(marker);

        if (!isAverageCenter) {

            if (mCenter == null)
                this.mCenter = mMarkers.get(0).getPosition();
        } else {
            this.mCenter = calAverageCenter();
        }
    }

    public LatLng getmCenter() {
        return this.mCenter;
    }

    public void setmCenter(LatLng mCenter) {
        this.mCenter = mCenter;
    }

    public List<MarkerOptions> getmMarkers() {
        return mMarkers;
    }

    public void setmMarkers(List<MarkerOptions> mMarkers, Boolean isAverageCenter) {
        this.mMarkers.addAll(mMarkers);
        if (!isAverageCenter) {
            if (mCenter == null) {
                this.mCenter = mMarkers.get(0).getPosition();
            }
        } else
            this.mCenter = calAverageCenter();
    }

    public MBound getmGridBounds() {
        return mGridBounds;
    }

    public void setmGridBounds(MBound mGridBounds) {
        this.mGridBounds = mGridBounds;
    }
}

然后MainActivity类,

public class MainActivity extends Activity {

    private String TAG = "MainActivity";

    private MapView mMapView;
    private Boolean isAverageCenter = false;
    private Integer mMaxZoom = 12;
    private Integer mGridSize = 60;
    private ArrayList<MarkerOptions> mMarkers;
    private Cluster mCluster;
    private double mDistance = 600000;
    private BaiduMap mBaiduMap;
    public LocationClient mLocationClient = null;
    public BDLocationListener myLocationListener = null;


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

        init();
        // 生产随机经纬度坐标
        addFakeDate();
        this.isAverageCenter = false;
        // 监听mapview
        setListener();
        LocationOrientate();
    }

    private void init() {
        mMapView = (MapView) findViewById(R.id.bmapView);
        mBaiduMap = mMapView.getMap();
        mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(5.0f));
        mCluster = new Cluster(this, mMapView, isAverageCenter, mGridSize, mDistance);
        mBaiduMap.clear();
    }

    /** * 创建虚拟数据 */
    private void addFakeDate() {
        mMarkers = new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            LatLng pt = new LatLng(((Math.random() * 30 + 15)), ((Math.random() * 25 + 95)));
            MarkerOptions item = new MarkerOptions().position(pt)
                    .icon(BitmapDescriptorFactory.fromResource(R.drawable.nav_turn_via_1));
            mMarkers.add(item);
        }
    }

    /** * 在地图上显示标注点 * @param list 所有标注点 */
    private void pinMarkers(ArrayList<MarkerOptions> list) {
        this.mBaiduMap.clear();
        Log.e(TAG, "pinMarkers: size:" + list.size());
        for (int i = 0; i < list.size(); i++) {
            this.mBaiduMap.addOverlay(list.get(i));
        }
        mMapView.refreshDrawableState();
    }

    private void setListener() {

        //点击标注点放大
        mBaiduMap.setOnMarkerClickListener(new BaiduMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                if (mBaiduMap.getMapStatus().zoom < mBaiduMap.getMaxZoomLevel()) {
                    float newZoom = mBaiduMap.getMapStatus().zoom + 2.0f;
                    mBaiduMap.setMapStatus(MapStatusUpdateFactory.zoomTo(newZoom));
                }
                return false;
            }
        });

        //地图加载结束时显示标注点
        mBaiduMap.setOnMapLoadedCallback(new BaiduMap.OnMapLoadedCallback() {
            @Override
            public void onMapLoaded() {
                refreshMarks();
            }
        });

        //地图状态改变时重新绘制标注点
        mBaiduMap.setOnMapStatusChangeListener(new BaiduMap.OnMapStatusChangeListener() {
            @Override
            public void onMapStatusChangeStart(MapStatus mapStatus) {

            }

            @Override
            public void onMapStatusChange(MapStatus mapStatus) {

            }

            @Override
            public void onMapStatusChangeFinish(MapStatus mapStatus) {
                refreshMarks();
            }
        });

    }

    /** * 如果当前地图缩放程度超过设置的最大值,则不改变点坐标,否则重新进行聚合运算 */
    private void refreshMarks() {
        if (mBaiduMap.getMapStatus().zoom >= MainActivity.this.mMaxZoom) {
            mBaiduMap.clear();
            pinMarkers(refreshVersionClusterMarker(mMarkers));
        } else {
            ArrayList<MarkerOptions> clusters = mCluster.createCluster(refreshVersionClusterMarker(mMarkers));
            mBaiduMap.clear();
            pinMarkers(clusters);
        }
    }

    private void LocationOrientate() {
        mLocationClient = new LocationClient(MainActivity.this);
        myLocationListener = new MyLocationListener();
        mLocationClient.registerLocationListener(myLocationListener);

        LocationClientOption option = new LocationClientOption();
        option.setAddrType("all");
        option.setProdName("定位GPS");
        option.setOpenGps(true);
        option.setCoorType("bd09ll");
        mLocationClient.setLocOption(option);
        mLocationClient.start();

        mMapView.refreshDrawableState();
    }


    /** * 初始时定位到当前位置 */
    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            LatLng currentPosition = new LatLng(location.getLatitude(), location.getLongitude());
            mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(currentPosition));
        }
    }

    private ArrayList<MarkerOptions> refreshVersionClusterMarker(ArrayList<MarkerOptions> list) {
        MapStatus mapStatus = mBaiduMap.getMapStatus();
        LatLngBounds latLngBounds = mapStatus.bound;

        ArrayList<MarkerOptions> result = new ArrayList<MarkerOptions>();

        for (int i = 0; i < list.size(); i++) {
            if (latLngBounds.contains(list.get(i).getPosition())) {
                result.add(list.get(i));
            }
        }
        Log.e(TAG, "可见点:" + result.size());

        return result;

    }

}

MapUtils类

public class MapUtils {
    static double DEF_PI = 3.14159265359; // PI
    static double DEF_2PI = 6.28318530712; // 2*PI
    static double DEF_PI180 = 0.01745329252; // PI/180.0
    static double DEF_R = 6370693.5; // radius of earth

    public static MBound getExtendedBounds(MapView map, MBound bound,
                                           Integer gridSize) {
        MBound tbounds = cutBoundsInRange(bound);

        Projection projection = map.getMap().getProjection();
        Point pixelNE = projection.toScreenLocation(tbounds.getRightTop());
        Point pixelSW = projection.toScreenLocation(tbounds.getLeftBottom());
        pixelNE.x += gridSize;
        pixelNE.y -= gridSize;
        pixelSW.x -= gridSize;
        pixelSW.y += gridSize;
        LatLng rightTop = projection.fromScreenLocation(new Point(pixelNE.x, pixelNE.y));
        LatLng leftBottom = projection.fromScreenLocation(new Point(pixelSW.x, pixelSW.y));

        return new MBound(rightTop.latitude, rightTop.longitude, leftBottom.latitude, leftBottom.longitude);
    }

    public static MBound cutBoundsInRange(MBound bounds) {
        double maxX = getRange(bounds.getRightTopLat(),
                -74, 74);
        double minX = getRange(bounds.getRightTopLat(),
                -74, 740);
        double maxY = getRange(bounds.getRightTopLng(),
                -180, 180);
        double minY = getRange(bounds.getLeftBottomLng(),
                -180, 180);
        return new MBound(minX, minY, maxX, maxY);
    }

    public static double getRange(double i, double mix, double max) {
        i = Math.max(i, mix);
        i = Math.min(i, max);
        return i;
    }

    public static double GetShortDistance(double lon1, double lat1, double lon2,
                                          double lat2) {
        double ew1, ns1, ew2, ns2;
        double dx, dy, dew;
        double distance;

        ew1 = lon1 * DEF_PI180;
        ns1 = lat1 * DEF_PI180;
        ew2 = lon2 * DEF_PI180;
        ns2 = lat2 * DEF_PI180;

        dew = ew1 - ew2;

        if (dew > DEF_PI)
            dew = DEF_2PI - dew;
        else if (dew < -DEF_PI)
            dew = DEF_2PI + dew;
        dx = DEF_R * Math.cos(ns1) * dew;
        dy = DEF_R * (ns1 - ns2);

        distance = Math.sqrt(dx * dx + dy * dy);
        return distance;
    }

    public static double GetLongDistance(double lon1, double lat1, double lon2,
                                         double lat2) {
        double ew1, ns1, ew2, ns2;
        double distance;

        ew1 = lon1 * DEF_PI180;
        ns1 = lat1 * DEF_PI180;
        ew2 = lon2 * DEF_PI180;
        ns2 = lat2 * DEF_PI180;

        distance = Math.sin(ns1) * Math.sin(ns2) + Math.cos(ns1)
                * Math.cos(ns2) * Math.cos(ew1 - ew2);

        if (distance > 1.0)
            distance = 1.0;
        else if (distance < -1.0)
            distance = -1.0;

        distance = DEF_R * Math.acos(distance);
        return distance;
    }

    public static Bitmap convertViewToBitmap(View view) {
        view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache();
        Bitmap bitmap = view.getDrawingCache();

        return bitmap;
    }
}

MBound类

public class MBound {

    private double rightTopLat;
    private double rightTopLng;
    private double leftBottomLat;
    private double leftBottomLng;


    private LatLng rightTop;
    private LatLng leftBottom;


    public MBound(LatLng rightTop, LatLng leftBottom) {
        super();
        this.rightTop = rightTop;
        this.leftBottom = leftBottom;
        rightTopLat = rightTop.latitude;
        rightTopLng = rightTop.longitude;
        leftBottomLat = leftBottom.latitude;
        leftBottomLng = leftBottom.longitude;

    }

    public MBound(double rightTopLat, double rightTopLng, double leftBottomLat, double leftBottomLng) {
        this.rightTopLat = rightTopLat;
        this.rightTopLng = rightTopLng;
        this.leftBottomLat = leftBottomLat;
        this.leftBottomLng = leftBottomLng;
        rightTop = new LatLng(rightTopLat, rightTopLng);
        leftBottom = new LatLng(leftBottomLat, leftBottomLng);


    }

    public double getRightTopLat() {
        return rightTopLat;
    }

    public void setRightTopLat(int rightTopLat) {
        this.rightTopLat = rightTopLat;
    }

    public double getRightTopLng() {
        return rightTopLng;
    }

    public void setRightTopLng(int rightTopLng) {
        this.rightTopLng = rightTopLng;
    }

    public double getLeftBottomLat() {
        return leftBottomLat;
    }

    public void setLeftBottomLat(int leftBottomLat) {
        this.leftBottomLat = leftBottomLat;
    }

    public double getLeftBottomLng() {
        return leftBottomLng;
    }

    public void setLeftBottomLng(int leftBottomLng) {
        this.leftBottomLng = leftBottomLng;
    }

    public LatLng getRightTop() {
        return rightTop;
    }

    public void setRightTop(LatLng rightTop) {
        this.rightTop = rightTop;
    }

    public LatLng getLeftBottom() {
        return leftBottom;
    }

    public void setLeftBottom(LatLng leftBottom) {
        this.leftBottom = leftBottom;
    }

}

MyApplication类

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        SDKInitializer.initialize(getApplicationContext());
    }
}

界面代码:
activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <com.baidu.mapapi.map.MapView
        android:id="@+id/bmapView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />
</RelativeLayout>

drawable_mark.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:background="@null">
    <TextView  android:id="@+id/drawble_mark" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2" android:textSize="15sp" android:gravity="center" android:textColor="@android:color/white" android:background="@drawable/m0" />

</LinearLayout>

另外就是图片了,这里就不上传了,manifest配置和百度地图官方配置一样
最后加上demo链接
Android百度地图点集合MarkerClusterdemo

上一篇:React和JSX 下一篇:Android APK签名