Cómo dibujar polígono mano libre en Google mapa V2 en Android?

Quiero dibujar un Free Hand Polygon on the Map in Google Map V2 .

Esta tarea fue posible con Overlay Map V1, pero Google Map ha eliminado esa clase de V2. (Según este mapa de Google V2 tiene la clase Overlay de eliminación ).

Buen ejemplo para Google Map V1 para dibujar polígono de estilo libre.

En Map V2, podemos dibujar un polígono mediante programación con la ayuda de Google Official Doc, pero ¿qué debe hacer un usuario? He encontrado respuesta incierta para el mapa V2

Comencé con el mapa simple de Google y dibujo el polígono para hacer esto programmatically y está trabajando correctamente pero ahora estoy buscando cómo un usuario puede dibujar? No quiero dibujar basado en el marcador en el polígono.

 // 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); 

He hecho un montón de Investigación y Desarrollo sobre este tema, pero no conseguir una manera perfecta de implementar una cosa en Map V2.

Algunas preguntas

  • Cómo dibujar polígono freestyle en el mapa V2 (como podemos hacer con Map V1)?
  • ¿Hay algún truco o alternativa para lograr esto? Si es así, ¿cómo?
  • ¿Podemos obtener un evento táctil en el mapa y dibujar polígono?
  • ¿Es factible en el Mapa V2?
  • ¿Es posible con un evento táctil que devuelve una matriz de lat-long?
  • ¿Cómo puedo obtener Lat-long basado en coordenadas de pantalla en setOnDragListener ?

Cada nueva versión tiene algo extra en comparación con el anterior por lo que estoy esperando que yo pueda lograr lo mismo en Map v2 también.

No estoy pidiendo darme un cierto código de la muestra o fijar su código, apenas una dirección y una documentación apropiadas.

He proporcionado todos los documentos y pruebas que encontré durante la investigación y el desarrollo.

Después de pasar un día entero en Rnd y probar algunas alternativas he encontrado una solución. En realidad he encontrado dos alternativas para el mismo problema, pero me gustaría sugerir el uso de la alternativa 2, porque eso es realmente muy fácil en comparación con la alternativa 1 .

En realidad he encontrado la Alternativa 1 con la ayuda de TheLittleNaruto , AndroidHacker y algunos otros desarrolladores y Alternativa 2 con la ayuda de Khan así que gracias a todos.

Alternativa 1

Cómo dibujar estilo libre polígono en el mapa V2 (como podemos hacer con el mapa V1)? ¿Es factible en el Mapa V2?

Sí, eso es factible, pero no se puede obtener directamente OnTouch() & OnDraw() en el mapa. Así que debemos tener que pensar de alguna otra manera para lograr esto.

¿Hay algún truco o manera alternativa de lograr esto, si es así cómo?

Sí, Google Map V2 no admite OnTouch() o OnDraw() en un mapa con class="com.google.android.gms.maps.SupportMapFragment" por lo que tenemos que planificar un Fragmento personalizado.

¿Es posible devolver matriz de lat-largo con evento táctil?

Sí, si creamos cualquier fragmento de mapa personalizado y lo usamos, podemos obtener ese evento de Toque o Arrastre en el mapa.

¿Cómo puedo obtener base Lat-long en coordenadas de pantalla en setOnDragListener?

setOnDragListener devolverá las coordenadas de la pantalla (x, y) . Ahora para eso, hay algunas técnicas para convertir (x, y) a LatLng e incluyen la proyección junto con 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: } }); 

Como funciona ?

Como ya he mencionado antes, tenemos que crear una vista de raíz personalizada y usarla para obtener Touch o Drag Events en el mapa.

Paso 1: Creamos MySupportMapFragment extends SupportMapFragment y lo usaremos como nuestro archivo .xml

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

Paso 2: Crear un MapWrapperLayout extends FrameLayout para que podamos establecer un MapWrapperLayout extends FrameLayout o arrastrar el oyente dentro e incorporar su vista con vista de mapa. Por lo tanto, necesitamos una interfaz que vamos a utilizar en 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: } }); }} 

Referencia Link1 , Link2

Hasta aquí soy capaz de obtener LatLong basado en X, Y coordenadas de pantalla . Ahora solo tengo que guardarlo en Array . Ese arreglo será utilizado para dibujar en el mapa y finalmente parecerá un polígono de forma libre.

Introduzca aquí la descripción de la imagen

Espero que esto definitivamente le ayudará.

Actualizar:

Alternativa 2

Como sabemos, el diseño de la trama es un diseño transparente, por lo que he logrado esto usando la disposición del marco. En este caso, no es necesario crear un fragmento personalizado. Acabo de usar la disposición del marco como disposición de la raíz. Así que básicamente obtendré los eventos de tacto en el diseño de la raíz y que devolverán las coordenadas de la pantalla, ya que nos dieron en el fragmento personalizado anteriormente.

Ahora, he creado un botón dentro del "Free Draw". Así que cuando haga clic en que puede mover los dedos en el mapa y dibujar un polígono mano libre y que deshabilitará su mapa móvil en la pantalla. Cuando vuelve a hacer clic en el mismo botón, la pantalla pasa en modo ideal.

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 

// El botón cambiará el estado móvil del mapa

 btn_draw_State.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if (Is_MAP_Moveable != true) { Is_MAP_Moveable = true; } else { Is_MAP_Moveable = false; } } }); 

Toca Click de Frame Layout y con la ayuda de hacer alguna tarea

 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; } if (Is_MAP_Moveable == true) { return true; } else { return false; } } }); 

// Dibuja tu mapa

 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); } 

Sin embargo, ahora tienes que mantener tu lista mientras dibujas, por lo que tienes que borrar los datos de la lista anterior.

Compruebe esto .. Creo U son capaces de mostrar Google Map v2

Compruebe el método "decodePoly" y "drawPath" en AsyncTask

Principales énfasis en "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); 

Clase completa para su referencia ..

 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 } } 

Espero eso ayude. ¡Aclamaciones!

ACTUALIZAR

Echa un vistazo a esto .. Creando OnDragListener para Google Map v2 Fragmento

También compruebe éste. Cómo dibujar una forma en el fragmento del mapa tocando con google map V2

Un poco más de referencia .. Cómo obtener coordenadas de pantalla de marcador en google maps v2 android

Así que tenemos alguna solución para la mano libre dibujar en el mapa v2. Implemente GoogleMap.OnMarkerDragListener en la actividad del mapa. Anulará la función 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)); } } 

Puede pasar algún tipo de hack de mano libre como tan pronto como el usuario toque el mapa, tendrá que detectar que las coordenadas y pasarlo a la onMarkerDrag. Como usted tendrá que utilizar la información del área para el proceso adicional. Para el evento táctil puedes implementar GoogleMap.OnMapClickListener y obtener las coordenadas de su parámetro. Espero que esto ayude 🙂

Esto es google maps API V2 tutorial:

 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 ); } } 

Enlace: https://developers.google.com/maps/documentation/android/

  • ¿Cómo puedo dibujar una flecha que muestre la dirección de manejo en MapView?
  • Dibujar una superposición similar a MapsApp
  • Mi superposición no aparece hasta que se pulse mapView en android
  • Android ViewPager: fragmentos superpuestos cuando el ancho de página se establece en 90%
  • Superponer una actividad en otra actividad O superponer una vista sobre otra
  • No entiende el método drawAt () para com.google.android.maps.Overlay
  • ¿Cómo puedo poner una vista encima de un glSurfaceView con un fondo transparente?
  • Widget flotante / superposición en el lanzador de Android
  • Custom OverlayItem sin dibujar
  • RelativaLayout TextView superposición
  • Lista de clics dentro de OverlayItem (MapView para Android)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.