需要實作的功能
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);
}
}