web-dev-qa-db-fra.com

Comment dessiner un polygone à main libre dans Google map V2 dans Android?

Je veux dessiner un Free Hand Polygon on the Map in Google Map V2.

Cette tâche était possible avec Overlay Map V1 mais Google Map a supprimé cette classe de V2. (Par ceci Google Map V2 a Remove Overlay Class ).

Bon exemple pour Google Map V1 pour dessiner un polygone de style libre.

Dans la carte V2, nous pouvons dessiner un polygone par programmation à l'aide de Google Official Doc mais que doit faire un utilisateur? J'ai trouvé réponse peu claire pour la carte V2

J'ai commencé avec Google Map simple et dessiner un polygone pour le faire par programme et cela fonctionne correctement, mais maintenant je cherche comment un utilisateur peut dessiner? Je ne veux pas dessiner sur la base du marqueur sur le polygone.

// Instantiates a new Polygon object and adds points to define a rectangle
PolygonOptions rectOptions = new PolygonOptions()
              .add(new LatLng(37.35, -122.0),
                   new LatLng(37.45, -122.0),
                   new LatLng(37.45, -122.2),
                   new LatLng(37.35, -122.2),
                   new LatLng(37.35, -122.0));

// Get back the mutable Polygon
Polygon polygon = myMap.addPolygon(rectOptions);

J'ai fait beaucoup de recherche et développement sur ce sujet, mais je n'ai pas réussi à implémenter une telle chose dans Map V2.

Quelques questions

  • Comment dessiner un polygone de style libre dans la carte V2 (comme nous pouvons le faire avec la carte V1)?
  • Y a-t-il une astuce ou une alternative pour y parvenir? Si oui comment?
  • Pouvons-nous obtenir un événement tactile sur la carte et dessiner un polygone?
  • Est-ce faisable dans la carte V2?
  • Est-il possible avec un événement tactile qui renvoie un tableau de lat-long?
  • Comment puis-je obtenir Lat-long basé sur les coordonnées de l'écran sur setOnDragListener?

Chaque nouvelle version a quelque chose de plus par rapport à l'ancienne, donc je m'attends à ce que je puisse réaliser la même chose dans Map v2 également.

Je ne demande pas de me donner un exemple de code ou de poster votre code, juste une bonne direction et documentation.

J'ai fourni tous les documents et preuves que j'ai trouvés pendant la recherche et le développement.

53
Chintan Khetiya

Après avoir passé une journée entière dans Rnd et testé quelques alternatives, j'ai trouvé une solution. En fait, j'ai trouvé deux alternatives pour le même problème, mais je voudrais suggérer l'utilisation de Alternative 2 car c'est vraiment très facile par rapport à Alternative 1 .

En fait, j'ai trouvé Alternative 1 avec l'aide de TheLittleNaruto , AndroidHacker et d'autres développeurs et Alternative 2 avec l'aide de Khan donc merci à tous.

Alternative 1

Comment dessiner un polygone de style libre dans la carte V2 (comme nous pouvons le faire avec la carte V1)? Est-ce faisable dans la carte V2?

Oui, c'est faisable mais vous ne pouvez pas obtenir directement OnTouch() & OnDraw() sur la carte. Nous devons donc penser à un autre moyen d'y parvenir.

Existe-t-il une astuce ou un moyen alternatif pour y parvenir, si oui comment?

Oui, Google Map V2 ne prend pas en charge OnTouch() ou OnDraw() sur une carte à l'aide de class="com.google.Android.gms.maps.SupportMapFragment" nous devons donc planifier un fragment personnalisé.

Est-il possible de retourner un tableau de lat-long avec un événement tactile?

Oui, si nous créons un fragment de carte personnalisé et l'utilisons, nous pouvons obtenir que Appuyez sur ou Faites glisser événement sur la carte.

Comment obtenir une base de lat sur les coordonnées d'écran sur setOnDragListener?

setOnDragListener renverra les coordonnées de l'écran (x, y) . Maintenant, pour cela, il existe quelques techniques pour convertir (x, y) en LatLng et ils incluent Projection avec Point & LatLng .

customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {@Override
    public void onDrag(MotionEvent motionEvent) {
        Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));
        Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));

        float x = motionEvent.getX(); // get screen x position or coordinate 
        float y = motionEvent.getY();  // get screen y position or coordinate 

        int x_co = Integer.parseInt(String.valueOf(Math.round(x))); // casting float to int 
        int y_co = Integer.parseInt(String.valueOf(Math.round(y))); // casting float to int 

        projection = mMap.getProjection(); // Will convert your x,y to LatLng
        Point x_y_points = new Point(x_co, y_co);// accept int x,y value
        LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points); // convert x,y to LatLng
        latitude = latLng.latitude; // your latitude 
        longitude = latLng.longitude; // your longitude 

        Log.i("ON_DRAG", "lat:" + latitude);
        Log.i("ON_DRAG", "long:" + longitude);

        // Handle motion event:
    }
});

Comment ça marche ?

Comme je l'ai déjà mentionné auparavant, nous devons créer une vue racine personnalisée et en utilisant cela, nous pouvons obtenir Touch ou Faites glisser les événements sur la carte.

Étape 1: nous créons MySupportMapFragment extends SupportMapFragment et nous l'utiliserons comme fichier .xml

 <fragment
        Android:id="@+id/map"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        class="pkg_name.MySupportMapFragment" /> 

Étape 2: créer un MapWrapperLayout extends FrameLayout afin que nous puissions définir un écouteur tactile ou glisser à l'intérieur et incorporer sa vue avec la vue de la carte. Donc, nous avons besoin d'une interface que nous utiliserons dans Root_Map.Java

MySupportMapFragment.Java

public class MySupportMapFragment extends SupportMapFragment {
    public View mOriginalContentView;
    public MapWrapperLayout mMapWrapperLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

        mOriginalContentView = super.onCreateView(inflater, parent, savedInstanceState);
        mMapWrapperLayout = new MapWrapperLayout(getActivity());
        mMapWrapperLayout.addView(mOriginalContentView);
        return mMapWrapperLayout;
    }

    @Override
    public View getView() {
        return mOriginalContentView;
    }

    public void setOnDragListener(MapWrapperLayout.OnDragListener onDragListener) {
        mMapWrapperLayout.setOnDragListener(onDragListener);
    }
}

MapWrapperLayout.Java

    public class MapWrapperLayout extends FrameLayout {
     private OnDragListener mOnDragListener;

     public MapWrapperLayout(Context context) {
         super(context);
     }

     public interface OnDragListener {
         public void onDrag(MotionEvent motionEvent);
     }

     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
         if (mOnDragListener != null) {
             mOnDragListener.onDrag(ev);
         }
         return super.dispatchTouchEvent(ev);
     }

     public void setOnDragListener(OnDragListener mOnDragListener) {
         this.mOnDragListener = mOnDragListener;
     }

 }

Root_Map.Java

public class Root_Map extends FragmentActivity {

    private GoogleMap mMap;
    public static boolean mMapIsTouched = false;
    MySupportMapFragment customMapFragment;
    Projection projection;
    public double latitude;
    public double longitude;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.root_map);
        MySupportMapFragment customMapFragment = ((MySupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
        mMap = customMapFragment.getMap();

        customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {               @Override
            public void onDrag(MotionEvent motionEvent) {
                Log.i("ON_DRAG", "X:" + String.valueOf(motionEvent.getX()));
                Log.i("ON_DRAG", "Y:" + String.valueOf(motionEvent.getY()));

                float x = motionEvent.getX();
                float y = motionEvent.getY();

                int x_co = Integer.parseInt(String.valueOf(Math.round(x)));
                int y_co = Integer.parseInt(String.valueOf(Math.round(y)));

                projection = mMap.getProjection();
                Point x_y_points = new Point(x_co, y_co);
                LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);
                latitude = latLng.latitude;
                longitude = latLng.longitude;

                Log.i("ON_DRAG", "lat:" + latitude);
                Log.i("ON_DRAG", "long:" + longitude);

                // Handle motion event:
            }
        });
    }}

Référence Link1 , Link2

Jusqu'à présent, je peux obtenir LatLong basé sur les coordonnées d'écran X, Y . Il ne me reste plus qu'à le stocker dans Array . Ce tableau sera utilisé pour dessiner sur la carte et, enfin, il ressemblera à un polygone de forme libre.

enter image description here

J'espère que cela vous aidera certainement.

Mise à jour:

Alternative 2

Comme nous le savons, La disposition des cadres est une disposition transparente, j'ai donc réalisé cela en utilisant la disposition des cadres. Dans ce cas, il n'est pas nécessaire de créer un fragment personnalisé. Je viens d'utiliser la disposition des cadres comme disposition racine. Donc, fondamentalement, j'obtiendrai les événements tactiles dans la disposition racine et cela renverra les coordonnées de l'écran, comme nous l'avons obtenu dans le fragment personnalisé précédemment.

Maintenant, j'ai créé un bouton dans le "Free Draw". Ainsi, lorsque vous cliquez dessus, vous pouvez déplacer vos doigts sur la carte et dessiner un polygone à main libre, ce qui désactivera le déplacement de votre carte à l'écran. Lorsque vous cliquez à nouveau sur le même bouton, l'écran passe en mode idéal.

root_map.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="fill_parent"
    Android:layout_height="fill_parent" >

    <fragment
        Android:id="@+id/map"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent"
        class="com.google.Android.gms.maps.SupportMapFragment" />

    <FrameLayout
        Android:id="@+id/fram_map"
        Android:layout_width="fill_parent"
        Android:layout_height="fill_parent" >

        <Button
            Android:id="@+id/btn_draw_State"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="Free Draw" />
    </FrameLayout>

</FrameLayout>

Root_Map.Java

FrameLayout fram_map = (FrameLayout) findViewById(R.id.fram_map);
Button btn_draw_State = (Button) findViewById(R.id.btn_draw_State);
Boolean Is_MAP_Moveable = false; // to detect map is movable 

// Le bouton changera l'état mobile de la carte

btn_draw_State.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Is_MAP_Moveable = !Is_MAP_Moveable;
    }
});

Appuyez sur Click of Frame Layout et à l'aide de la tâche

fram_map.setOnTouchListener(new View.OnTouchListener() {     @Override
    public boolean onTouch(View v, MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        int x_co = Math.round(x);
        int y_co = Math.round(y);

        projection = mMap.getProjection();
        Point x_y_points = new Point(x_co, y_co);

        LatLng latLng = mMap.getProjection().fromScreenLocation(x_y_points);
        latitude = latLng.latitude;

        longitude = latLng.longitude;

        int eventaction = event.getAction();
        switch (eventaction) {
            case MotionEvent.ACTION_DOWN:
                // finger touches the screen
                val.add(new LatLng(latitude, longitude));

            case MotionEvent.ACTION_MOVE:
                // finger moves on the screen
                val.add(new LatLng(latitude, longitude));

            case MotionEvent.ACTION_UP:
                // finger leaves the screen
                Draw_Map();
                break;
        }

        return Is_MAP_Moveable;

    }
});

// Dessine ta carte

public void Draw_Map() {
    rectOptions = new PolygonOptions();
    rectOptions.addAll(val);
    rectOptions.strokeColor(Color.BLUE);
    rectOptions.strokeWidth(7);
    rectOptions.fillColor(Color.CYAN);
    polygon = mMap.addPolygon(rectOptions);
}

Pourtant, maintenant vous devez maintenir votre liste pendant que vous dessinez, vous devez donc effacer les données de votre liste précédente.

73
Chintan Khetiya

Vérifiez ceci .. Je crois que U est capable d'afficher Google Map v2

Découvrez la méthode "decodePoly" et "drawPath" dans AsyncTask

Impulsion principale dans "drawPath" ..

PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
for (int z = 0; z < list.size(); z++) {
    LatLng point = list.get(z);
    options.add(point);
}
line = myMap.addPolyline(options);

Classe complète pour votre référence ..

package com.example.androidhackergooglemap;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStream;
import Java.io.InputStreamReader;
import Java.io.UnsupportedEncodingException;
import Java.util.ArrayList;
import Java.util.List;

import org.Apache.http.HttpEntity;
import org.Apache.http.HttpResponse;
import org.Apache.http.client.ClientProtocolException;
import org.Apache.http.client.methods.HttpPost;
import org.Apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;

import com.google.Android.gms.maps.CameraUpdateFactory;
import com.google.Android.gms.maps.GoogleMap;
import com.google.Android.gms.maps.SupportMapFragment;
import com.google.Android.gms.maps.model.BitmapDescriptorFactory;
import com.google.Android.gms.maps.model.LatLng;
import com.google.Android.gms.maps.model.Marker;
import com.google.Android.gms.maps.model.MarkerOptions;
import com.google.Android.gms.maps.model.Polyline;
import com.google.Android.gms.maps.model.PolylineOptions;

import Android.app.ProgressDialog;
import Android.content.Context;
import Android.content.Intent;
import Android.graphics.Color;
import Android.location.Location;
import Android.location.LocationManager;
import Android.os.AsyncTask;
import Android.os.Bundle;
import Android.provider.Settings;
import Android.support.v4.app.FragmentActivity;
import Android.util.Log;
import Android.view.View;
import Android.view.View.OnClickListener;
import Android.widget.Toast;

public class MainActivity extends FragmentActivity implements OnClickListener {

    private GoogleMap myMap;
    Polyline line;
    Context context;

    Location location;
    boolean check_provider_enabled = false;

    // Static LatLng
    LatLng startLatLng = new LatLng(30.707104, 76.690749);
    LatLng endLatLng = new LatLng(30.721419, 76.730017);

    public void onCreate(Bundle bd) {
        super.onCreate(bd);
        setContentView(R.layout.activity_main);
        context = MainActivity.this;

        // GoogleMap myMap
        myMap = ((SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map)).getMap();
        myMap.setMyLocationEnabled(true);
        myMap.moveCamera(CameraUpdateFactory.newLatLng(startLatLng));
        myMap.animateCamera(CameraUpdateFactory.zoomTo(12));

        LocationManager service = (LocationManager) getSystemService(LOCATION_SERVICE);
        boolean enabled = service.isProviderEnabled(LocationManager.GPS_PROVIDER);
        location = service.getLastKnownLocation(LocationManager.GPS_PROVIDER);

        // check if enabled and if not send user to the GSP settings
        // Better solution would be to display a dialog and suggesting to 
        // go to the settings
        if (!enabled) {
            /*Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);*/
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            startActivity(intent);
            Toast.makeText(getApplicationContext(), "Enable GPS servcies to use this app.", Toast.LENGTH_LONG).show();
        } else {
            try {
                String urlTopass = makeURL(startLatLng.latitude,
                    startLatLng.longitude, endLatLng.latitude,
                    endLatLng.longitude);
                new connectAsyncTask(urlTopass).execute();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // Now auto clicking the button
        // btntemp.performClick();
    }


    private class connectAsyncTask extends AsyncTask < Void, Void, String > {
        private ProgressDialog progressDialog;
        String url;

        connectAsyncTask(String urlPass) {
            url = urlPass;
        }

        @Override
        protected void onPreExecute() {
            // TODO Auto-generated method stub
            super.onPreExecute();
            progressDialog = new ProgressDialog(context);
            progressDialog.setMessage("Fetching route, Please wait...");
            progressDialog.setIndeterminate(true);
            progressDialog.show();
        }

        @Override
        protected String doInBackground(Void...params) {
            JSONParser jParser = new JSONParser();
            String json = jParser.getJSONFromUrl(url);
            return json;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            progressDialog.hide();
            if (result != null) {
                drawPath(result);
            }
        }
    }

    public String makeURL(double sourcelat, double sourcelog, double destlat,
        double destlog) {
        StringBuilder urlString = new StringBuilder();
        urlString.append("http://maps.googleapis.com/maps/api/directions/json");
        urlString.append("?origin="); // from
        urlString.append(Double.toString(sourcelat));
        urlString.append(",");
        urlString.append(Double.toString(sourcelog));
        urlString.append("&destination="); // to
        urlString.append(Double.toString(destlat));
        urlString.append(",");
        urlString.append(Double.toString(destlog));
        urlString.append("&sensor=false&mode=driving&alternatives=true");
        return urlString.toString();
    }

    public class JSONParser {

        InputStream is = null;
        JSONObject jObj = null;
        String json = "";

        // constructor
        public JSONParser() {}

        public String getJSONFromUrl(String url) {

            // Making HTTP request
            try {
                // defaultHttpClient
                DefaultHttpClient httpClient = new DefaultHttpClient();
                HttpPost httpPost = new HttpPost(url);

                HttpResponse httpResponse = httpClient.execute(httpPost);
                HttpEntity httpEntity = httpResponse.getEntity();
                is = httpEntity.getContent();

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                BufferedReader reader = new BufferedReader(
                    new InputStreamReader(is, "iso-8859-1"), 8);
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }

                json = sb.toString();
                is.close();
            } catch (Exception e) {
                Log.e("Buffer Error", "Error converting result " + e.toString());
            }
            return json;
        }
    }

    public void drawPath(String result) {
        if (line != null) {
            myMap.clear();
        }
        myMap.addMarker(new MarkerOptions().position(endLatLng).icon(
            BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
        myMap.addMarker(new MarkerOptions().position(startLatLng).icon(
            BitmapDescriptorFactory.fromResource(R.drawable.ic_launcher)));
        try {
            // Tranform the string into a json object
            final JSONObject json = new JSONObject(result);
            JSONArray routeArray = json.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);
            JSONObject overviewPolylines = routes
                .getJSONObject("overview_polyline");
            String encodedString = overviewPolylines.getString("points");
            List < LatLng > list = decodePoly(encodedString);

            PolylineOptions options = new PolylineOptions().width(5).color(Color.BLUE).geodesic(true);
            for (int z = 0; z < list.size(); z++) {
                LatLng point = list.get(z);
                options.add(point);
            }
            line = myMap.addPolyline(options);

            /*for (int z = 0; z < list.size() - 1; z++) {
                LatLng src = list.get(z);
                LatLng dest = list.get(z + 1);
                line = myMap.addPolyline(new PolylineOptions()
                        .add(new LatLng(src.latitude, src.longitude),
                                new LatLng(dest.latitude, dest.longitude))
                        .width(5).color(Color.BLUE).geodesic(true));
            }*/

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List < LatLng > decodePoly(String encoded) {

        List < LatLng > poly = new ArrayList < LatLng > ();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                (((double) lng / 1E5)));
            poly.add(p);
        }

        return poly;
    }

    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
    }
}

J'espère que ça aide. À votre santé!

[~ # ~] mise à jour [~ # ~]

consultez ceci .. Création de OnDragListener pour Google Map v2 Fragment

Vérifiez également celui-ci .. Comment dessiner une forme sur le fragment de carte en le touchant en utilisant google map V2

Un peu plus de référence .. Comment obtenir les coordonnées d'écran du marqueur dans google maps v2 Android

3
AndroidHacker

Nous avons donc une solution pour dessiner à main levée sur la carte v2. Mettre en place GoogleMap.OnMarkerDragListener dans votre activité sur la carte. Il remplacera la fonction onMarkerDrag.

@Override
public void onMarkerDrag(Marker marker) {

   //add the marker's latlng in a arraylist of LatLng and pass it to the loop
    for (int i = 0; i < arraylistoflatlng.size(); i++) {
         myMap.addPolyline(new PolylineOptions()
        .addAll(arraylistoflatlng)
        .width(5)
        .color(Color.RED));
    }
    }

vous pouvez passer une sorte de piratage à main levée comme dès que l'utilisateur touchera la carte, vous devrez détecter ces coordonnées et les transmettre au onMarkerDrag. Comme vous devrez utiliser les informations de la zone pour poursuivre le processus. Pour l'événement tactile, vous pouvez implémenter GoogleMap.OnMapClickListener et obtenir les coordonnées de son paramètre. J'espère que cela vous aidera :)

2
TheLittleNaruto

voici le tutoriel google maps API V2:

public class MapPane extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map_activity);
        GoogleMap map = ((MapFragment) getFragmentManager()
                .findFragmentById(R.id.map)).getMap();

        map.moveCamera(CameraUpdateFactory.newLatLngZoom(
                new LatLng(-18.142, 178.431), 2));

        // Polylines are useful for marking paths and routes on the map.
        map.addPolyline(new PolylineOptions().geodesic(true)
                .add(new LatLng(-33.866, 151.195))  // Sydney
                .add(new LatLng(-18.142, 178.431))  // Fiji
                .add(new LatLng(21.291, -157.821))  // Hawaii
                .add(new LatLng(37.423, -122.091))  // Mountain View
        );
    }
}

lien: https://developers.google.com/maps/documentation/Android/

1
Nguyen Thanh An