需要实现的功能
1、按住多边形可自由拖动
2、长按多边形顶点可以自由拖动多边形顶点
3、点击多边形线条可以生成新的点
4、点击多边形顶点可以删除多边形顶点
先上效果图。
百度地图支持的各种地图覆盖物:地图标注(Marker)、几何图形(点、折线、弧线、多边形等)、POI检索结果覆盖物、线路规划结果覆盖物等。
自定义图层:定位图层、地形图图层、热力图图层、瓦片图层。
我使用的 百度地图版本:v5_0_0
代码可以查看github https://github.com/oldbirdy/polygonDemoByBaidu
首先在Application中初始化百度地图SDK
public class DemoApplication extends Application { @Override public void onCreate() { super.onCreate(); // 在使用 SDK 各组间之前初始化 context 信息,传入 ApplicationContext SDKInitializer.initialize(this); //自4.3.0起,百度地图SDK所有接口均支持百度坐标和国测局坐标,用此方法设置您使用的坐标类型. //包括BD09LL和GCJ02两种坐标,默认是BD09LL坐标。 SDKInitializer.setCoordType(CoordType.BD09LL); } }
Activity中处理覆盖物的拖拽
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_overlay); mMapView = (MapView) findViewById(R.id.bmapView); mBaiduMap = mMapView.getMap(); MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(14.0f); mBaiduMap.setMapStatus(msu); combinationOverlayList = new ArrayList<>(); initOverlay(); } //初始化基础数据 public void initOverlay() { LatLng llA = new LatLng(39.963175, 116.400244); LatLng llB = new LatLng(39.942821, 116.369199); LatLng llC = new LatLng(39.939723, 116.425541); LatLng llD = new LatLng(39.906965, 116.401394); list = new ArrayList<>(); list.add(llA); list.add(llB); list.add(llD); list.add(llC); final CombinationOverlay combinationOverlay = new CombinationOverlay(mMapView,list); combinationOverlayList.add(combinationOverlay); LatLng southwest = new LatLng(39.92235, 116.380338); LatLng northeast = new LatLng(39.947246, 116.414977); LatLngBounds bounds = new LatLngBounds.Builder().include(northeast) .include(southwest).build(); MapStatusUpdate u = MapStatusUpdateFactory .newLatLng(bounds.getCenter()); mBaiduMap.setMapStatus(u); mBaiduMap.setOnMapTouchListener(new BaiduMap.OnMapTouchListener() { @Override public void onTouch(MotionEvent motionEvent) { if(motionEvent.getAction()==MotionEvent.ACTION_DOWN){ //按下的时候 做处理 tempOverlay = null; lastx = motionEvent.getX(); lasty = motionEvent.getY(); Point point = new Point( (int)(motionEvent.getX()),(int) (motionEvent.getY())); LatLng latlng = mBaiduMap.getProjection().fromScreenLocation(point); // MapStatus.Builder builder = new MapStatus.Builder(); for(int i=0;i<combinationOverlayList.size();i++){ List<LatLng> list = combinationOverlayList.get(i).getLatLngList(); if(SpatialRelationUtil.isPolygonContainsPoint(list,latlng)){ //判断是否在多边形里面 //在多边形内部 // createPopupView("提示消息", new OnClickListener() { // @Override // public void onClick(View v) { // // } // }, new OnClickListener() { // @Override // public void onClick(View v) { // // } // }); // infoWindow = new InfoWindow(popupView,latlng,0); // mBaiduMap.showInfoWindow(infoWindow); tempOverlay = combinationOverlayList.get(i); mBaiduMap.getUiSettings().setScrollGesturesEnabled(false); mBaiduMap.hideInfoWindow(); break; } } }else if(motionEvent.getAction()==MotionEvent.ACTION_MOVE){ if(tempOverlay!=null){ //全部根据手指的移动将其转化成百度坐标 if(!isDrag){ offsetx = motionEvent.getX() - lastx; offsety = motionEvent.getY() - lasty; lastx = motionEvent.getX(); lasty = motionEvent.getY(); tempOverlay.updateOverlayByPolygon(offsetx,offsety); } } }else if(motionEvent.getAction()==MotionEvent.ACTION_UP){ if( tempOverlay != null){ mBaiduMap.getUiSettings().setScrollGesturesEnabled(true); } } } }); mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { } @Override public boolean onMapPoiClick(MapPoi mapPoi) { return false; } }); //Marker点击事件 mBaiduMap.setOnMarkerClickListener(new OnMarkerClickListener() { @Override public boolean onMarkerClick(Marker marker) { return updateMarkerClick(marker); } }); //markertu mBaiduMap.setOnMarkerDragListener(new OnMarkerDragListener() { public void onMarkerDrag(Marker marker) { updateMarkerDrag(marker); } public void onMarkerDragEnd(Marker marker) { isDrag = false; } public void onMarkerDragStart(Marker marker) { isDrag = true; } }); mBaiduMap.setOnMapClickListener(new BaiduMap.OnMapClickListener() { @Override public void onMapClick(LatLng latLng) { mBaiduMap.hideInfoWindow(); } @Override public boolean onMapPoiClick(MapPoi mapPoi) { return false; } }); mBaiduMap.setOnPolylineClickListener(new BaiduMap.OnPolylineClickListener() { @Override public boolean onPolylineClick(Polyline polyline) { mBaiduMap.hideInfoWindow(); return updateLineClick(polyline); } }); } /** * 更新marker点击 * @param marker * @return */ private boolean updateMarkerClick(final Marker marker) { for(int i=0;i < combinationOverlayList.size();i++){ if(combinationOverlayList.get(i).getMarkerList().contains(marker)){ Button button = new Button(getApplicationContext()); button.setBackgroundResource(R.drawable.popup); LatLng ll = marker.getPosition(); button.setText("删除当前点"); button.setTextColor(Color.BLACK); final int finalI = i; button.setOnClickListener(new OnClickListener() { public void onClick(View v) { combinationOverlayList.get(finalI).updateOverlayByRemoveOneMarker(marker); } }); infoWindow = new InfoWindow(button,ll,-47); mBaiduMap.showInfoWindow(infoWindow); return true; } } return false; } /** * 更新线段点击 * @param polyline * @return */ private boolean updateLineClick(Polyline polyline){ for(int i=0;i<combinationOverlayList.size();i++){ if(combinationOverlayList.get(i).getPolylineList().contains(polyline)){ combinationOverlayList.get(i).updateOverlayByLineClick(polyline); return true; } } return false; } private void updateMarkerDrag(Marker marker) { for(int i=0;i<combinationOverlayList.size();i++){ if(combinationOverlayList.get(i).getMarkerList().contains(marker)){ combinationOverlayList.get(i).updateOverlayByMarker(marker); } } }
自定义的一个组合覆盖物。会生成相应的覆盖物界面。根据覆盖物上的点,线,面的事件去更新整个覆盖物的状态
public class CombinationOverlay { private MapView mMapView; private BaiduMap mBaiduMap; private List<LatLng> latLngList; BitmapDescriptor bdA = BitmapDescriptorFactory .fromResource(R.drawable.icon_marka); private List<List<LatLng>> lineListList; private Polygon polygonOverlay; private List<Marker> markerList; private List<Polyline> polylineList; private Stroke stroke = new Stroke(5, 0xAA00FF00); public CombinationOverlay(MapView mMapView, List<LatLng> latLngList) { this.mMapView = mMapView; this.latLngList = latLngList; if(latLngList.size()<3){ throw new IllegalArgumentException("点数小于3,无法构成多边形"); } mBaiduMap = mMapView.getMap(); initZiyuan(); } private void initZiyuan() { PolygonOptions polygonOptions = new PolygonOptions(); polygonOptions.points(latLngList); polygonOptions.stroke(stroke); polygonOptions.fillColor(0xAAFFFF00); polygonOverlay = (Polygon)mBaiduMap.addOverlay(polygonOptions); markerList = new ArrayList<>(); for(int i = 0;i < latLngList.size();i++){ // latLngList = MarkerOptions markerOptions = new MarkerOptions().position(latLngList.get(i)).icon(bdA).draggable(true); Marker marker= (Marker)mBaiduMap.addOverlay(markerOptions); markerList.add(marker); } lineListList = new ArrayList<>(); polylineList = new ArrayList<>(); for(int i=0;i<latLngList.size();i++){ List<LatLng> latLngLineList = new ArrayList<>(); latLngLineList.add(latLngList.get(i)); if(i < latLngList.size()-1){ latLngLineList.add(latLngList.get(i+1)); }else{ latLngLineList.add(latLngList.get(0)); } lineListList.add(latLngLineList); PolylineOptions polylineOptions = new PolylineOptions().points(latLngLineList).color(0xAAFFFF00).focus(true).width(10); Polyline polyline = (Polyline)mBaiduMap.addOverlay(polylineOptions); polylineList.add(polyline); } } public Polygon getPolygonOverlay() { return polygonOverlay; } public void setPolygonOverlay(Polygon polygonOverlay) { this.polygonOverlay = polygonOverlay; } public List<Marker> getMarkerList() { return markerList; } public void setMarkerList(List<Marker> markerList) { this.markerList = markerList; } public List<Polyline> getPolylineList() { return polylineList; } public void setPolylineList(List<Polyline> polylineList) { this.polylineList = polylineList; } public List<LatLng> getLatLngList() { return latLngList; } /** * 更新覆盖物的位置 */ public void updateOverlayByMarker(Marker marker){ int position = markerList.indexOf(marker); if(position==-1){ return; } latLngList.set(position,marker.getPosition()); polygonOverlay.setPoints(latLngList); if(position==0){ //第一个点 更新第一条线和最后一条线 lineListList.get(position).set(0,marker.getPosition()); //更新第一个点的坐标 polylineList.get(position).setPoints(lineListList.get(position)); lineListList.get(lineListList.size()-1).set(1,marker.getPosition()); //更新第二个点 polylineList.get(polylineList.size()-1).setPoints(lineListList.get(polylineList.size()-1 )); }else{ lineListList.get(position).set(0,marker.getPosition()); //更新第一个点 polylineList.get(position).setPoints(lineListList.get(position)); lineListList.get(position-1).set(1,marker.getPosition()); polylineList.get(position-1).setPoints(lineListList.get(position-1)); } } /** * 根据偏移量更新显示位置 * @param offsetx * @param offsety */ public void updateOverlayByPolygon(float offsetx,float offsety){ latLngList = MapUtils.getLatLngByOffset(mMapView,latLngList,offsetx,offsety); polygonOverlay.setPoints( latLngList); for(int i=0;i < markerList.size();i++){ markerList.get(i).setPosition(latLngList.get(i)); } lineListList.clear(); for(int i=0;i<latLngList.size();i++){ List<LatLng> latLngLineList = new ArrayList<>(); latLngLineList.add(latLngList.get(i)); if(i < latLngList.size()-1){ latLngLineList.add(latLngList.get(i+1)); }else{ latLngLineList.add(latLngList.get(0)); } lineListList.add(latLngLineList); polylineList.get(i).setPoints(latLngLineList); } // } /** * 点击线条触发 * @param polyline */ public void updateOverlayByLineClick(Polyline polyline){ int positon = polylineList.indexOf(polyline); if(-1==positon){ return; } LatLng latLng = MapUtils.getCenterOfLines(mMapView,polyline.getPoints()); //得到中心点 latLngList.add(positon+1,latLng); removeCombinationOverlay(); initZiyuan(); } public void updateOverlayByRemoveOneMarker(Marker marker){ int positon = markerList.indexOf(marker); if(-1==positon){ return; } if(markerList.size()<4){ Toast.makeText(mMapView.getContext(), "不能移除当前点,移除后无法构成多边形", Toast.LENGTH_SHORT).show(); }else{ latLngList.remove(positon); removeCombinationOverlay(); initZiyuan(); } mBaiduMap.hideInfoWindow(); } /** * 移除覆盖物 */ public void removeCombinationOverlay(){ polygonOverlay.remove(); for(int i=0;i<markerList.size();i++){ markerList.get(i).remove(); } for(int i=0;i<polylineList.size();i++){ polylineList.get(i).remove(); } markerList.clear(); polylineList.clear(); lineListList.clear(); } }一个工具类:
public class MapUtils { /** * 获取线段中心点坐标 * @param mPoints * @return */ public static LatLng getCenterOfLines(MapView mapView, @Size(2) List<LatLng> mPoints){ if(mPoints.size()!=2){ throw new IllegalArgumentException("线段点个数应为2个"); } Projection projection = mapView.getMap().getProjection(); Point point0 = projection.toScreenLocation(mPoints.get(0)); Point point1 = projection.toScreenLocation(mPoints.get(1)); Point point = getCenterOfScrrenTwoPoint(point0,point1); return projection.fromScreenLocation(point); } /** * 获取屏幕上两点的中心坐标 * @return */ public static Point getCenterOfScrrenTwoPoint(Point point0,Point point1){ return new Point((int)((point0.x+point1.x)/2),(int)((point0.y+point1.y)/2)); } /** * 根据偏移量获取新的坐标值 * @param list * @param offsetx * @param offsety * @return */ public static List<LatLng> getLatLngByOffset(MapView mapView,List<LatLng> list,float offsetx,float offsety){ Projection projection = mapView.getMap().getProjection(); for(int i=0;i<list.size();i++){ Point tempPoint = projection.toScreenLocation(list.get(i)); tempPoint.offset((int)offsetx,(int)offsety); list.set(i,projection.fromScreenLocation(tempPoint)); } return list; } //计算多边形重心 也可计算面积 public static LatLng getCenterOfGravityPoint(List<LatLng> mPoints) { double area = 0.0;//多边形面积 double Gx = 0.0, Gy = 0.0;// 重心的x、y for (int i = 1; i <= mPoints.size(); i++) { double iLat = mPoints.get(i % mPoints.size()).latitude; double iLng = mPoints.get(i % mPoints.size()).longitude; double nextLat = mPoints.get(i - 1).latitude; double nextLng = mPoints.get(i - 1).longitude; double temp = (iLat * nextLng - iLng * nextLat) / 2.0; area += temp; Gx += temp * (iLat + nextLat) / 3.0; Gy += temp * (iLng + nextLng) / 3.0; } Gx = Gx / area; Gy = Gy / area; return new LatLng(Gx, Gy); } }