Search code examples
androidgoogle-mapsandroid-maps-v2

Editable multiple polygon using dragListener in Google Maps


I would like to implement multiple polygons with an editable using a drag listener. I am able to draw the multiple polygons but I don't know how to make editable.

I am able to move marker for current polygon but when I try to move previous polygon’s marker app is crash. I tried with saving polygon list but I can not able to drag the marker.

please see my code HERE.

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (readyToGo()) {
            setContentView(R.layout.activity_maps);
            // Obtain the SupportMapFragment and get notified when the map is ready to be used.
            SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                    .findFragmentById(R.id.map);
            mapFragment.getMapAsync(this);

            if (savedInstanceState == null) {
                mapFragment.getMapAsync(this);
            }

            mapFragment.getMapAsync(this);
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        CameraUpdate center =
                CameraUpdateFactory.newLatLng(new LatLng(40.76793169992044,
                        -73.98180484771729));
        CameraUpdate zoom = CameraUpdateFactory.zoomTo(15);
        mMap.moveCamera(center);
        mMap.animateCamera(zoom);
        mMap.setIndoorEnabled(false);

        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {

                Marker marker = mMap.addMarker(new MarkerOptions().position(latLng).draggable(true));
                marker.setTag(latLng);
                markerList.add(marker);
                points.add(latLng);
                drawPolygon(points);
            }
        });


        mMap.setOnMarkerDragListener(new GoogleMap.OnMarkerDragListener() {
            @Override
            public void onMarkerDragStart(Marker marker) {

            }

            @Override
            public void onMarkerDrag(Marker marker) {
                updateMarkerLocation(marker, false);
            }

            @Override
            public void onMarkerDragEnd(Marker marker) {
                updateMarkerLocation(marker, true);

            }
        });

    }

    public void closePolygon(View view) {

    }

    public void newPolygon(View view) {

//
        points.clear();
        markerList.clear();
        polygon = null;
//        mMap.clear();
    }

    private void updateMarkerLocation(Marker marker, boolean calculate) {
        LatLng latLng = (LatLng) marker.getTag();
        int position = points.indexOf(latLng);
        points.set(position, marker.getPosition());
        marker.setTag(marker.getPosition());
        drawPolygon(points);

    }

    private void drawPolygon(List<LatLng> latLngList) {
        if (polygon != null) {
            polygon.remove();
        }
        polygonOptions = new PolygonOptions();
        polygonOptions.addAll(latLngList);
        polygon = mMap.addPolygon(polygonOptions);

    }

}

Solution

  • Basically this approach keeps the markers and points as collections associated with each polygon. It simplifies things by assuming after 5 markers a new polygon is created (equivalent to an add polygon).

    UPDATED: To use the "new polygon" button as defined in the layout in github. Button listener just sets a flag and instead of using a size=5 check replace the check with the flag.

    A map from any marker to its corresponding list is maintained for use in the updateMarkerLocation method.

    All of this is predicated on the fact that any marker has a unique id provided by the map API getId() which in practice is a string like "m7".

    I've listed the parts updated:

    // Map a marker id to its corresponding list (represented by the root marker id)
    HashMap<String,String> markerToList = new HashMap<>();
    
    // A list of markers for each polygon (designated by the marker root).
    HashMap<String,List<Marker>> polygonMarkers = new HashMap<>();
    
    // A list of polygon points for each polygon (designed by the marker root).
    HashMap<String,List<LatLng>> polygonPoints = new HashMap<>();
    
    // List of polygons (designated by marker root).
    HashMap<String,Polygon> polygons = new HashMap<>();
    
    // The active polygon (designated by marker root) - polygon added to.
    String markerListKey;
    
    // Flag used to record when the 'New Polygon' button is pressed.  Next map
    // click starts a new polygon.
    boolean newPolygon = false;
    
    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;
        CameraUpdate center =
                CameraUpdateFactory.newLatLng(new LatLng(40.76793169992044,
                        -73.98180484771729));
        CameraUpdate zoom = CameraUpdateFactory.zoomTo(15);
        mMap.moveCamera(center);
        mMap.animateCamera(zoom);
        mMap.setIndoorEnabled(false);
    
        Button b = findViewById(R.id.bt_new_polygon);
        b.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                newPolygon = true;
            }
        });
    
        mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
    
                Marker marker = mMap.addMarker(new MarkerOptions().position(latLng).draggable(true));
                marker.setTag(latLng);
    
                // Special case for very first marker.
                if (polygonMarkers.size() == 0) {
                    polygonMarkers.put(marker.getId(),new ArrayList<Marker>());
                    // only 0 or 1 polygons so just add it to new one or existing one.
                    markerList = new ArrayList<>();
                    points = new ArrayList<>();
                    polygonMarkers.put(marker.getId(),markerList);
                    polygonPoints.put(marker.getId(),points);
                    markerListKey = marker.getId();
                }
    
                if (newPolygon) {
                    newPolygon = false;
                    markerList = new ArrayList<>();
                    points = new ArrayList<>();
                    polygonMarkers.put(marker.getId(),markerList);
                    polygonPoints.put(marker.getId(),points);
                    markerListKey = marker.getId();
                }
    
                markerList.add(marker);
                points.add(latLng);
                markerToList.put(marker.getId(),markerListKey);
    
                drawPolygon(markerListKey, points);
            }
        });
    
    
    private void updateMarkerLocation(Marker marker, boolean calculate) {
    
        // Use the marker to figure out which polygon list to use...
        List<LatLng> pts = polygonPoints.get(markerToList.get(marker.getId()));
        
        // This is much the same except use the retrieved point list.
        LatLng latLng = (LatLng) marker.getTag();
        int position = pts.indexOf(latLng);
        pts.set(position, marker.getPosition());
        marker.setTag(marker.getPosition());
        drawPolygon(markerToList.get(marker.getId()),pts);
    
    }
    
    private void drawPolygon(String mKey, List<LatLng> latLngList) {
    
        // Use the existing polygon (if any) for the root marker.
        Polygon polygon = polygons.get(mKey);
        if (polygon != null) {
            polygon.remove();
        }
        polygonOptions = new PolygonOptions();
        polygonOptions.addAll(latLngList);
        polygon = mMap.addPolygon(polygonOptions);
        
        // And update the list for the root marker.
        polygons.put(mKey,polygon);
    }
    

    Initial

    Initial collection of 3 polygons added by clicking on map...

    enter image description here

    Modified

    Then an image showing a point in each polygon stretched...

    enter image description here