Как нарисовать многоугольник свободной руки в Google map V2 В Android?
Я хочу нарисовать Free Hand Polygon on the Map in Google Map V2
.
эта задача была возможна с Overlay
Map V1 но Google Map удалил этот класс из V2. (На этой карте Google V2 есть удалить класс наложения).
хороший пример для Google Map V1, чтобы нарисовать полигон свободного стиля.
В Map V2, мы можем нарисовать полигон программно с помощью Официальный Документ Google но что делать? Я нашел неясный ответ для карты V2
Я начал с простого Google Map & draw polygon, чтобы сделать это программно, и он работает правильно, но теперь я ищу, как пользователь может рисовать? Я не хочу рисовать на основе маркера на полигоне.
// 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);
Я сделал много исследований и разработок по этой теме, но не получил идеальный способ реализовать такую вещь в Map V2.
Несколько Вопросов
- как рисовать фристайл полигон в карте V2 (как мы можем сделать с картой V1)?
- есть ли какой-либо трюк или Альтернатива для достижения этого? Если да, то как?
- можем ли мы получить сенсорное событие на карте и нарисовать полигон?
- возможно ли это в Map V2?
- возможно ли с сенсорным событием, которое возвращает массив lat-long?
- как я могу получить Lat-long на основе координат экрана на
setOnDragListener
?
каждая новая версия имеет что-то дополнительное по сравнению со старым, поэтому я я ожидаю, что я могу достичь того же самого в Map v2 также.
Я не прошу дать мне какой-то пример кода или опубликовать ваш код, просто какое-то правильное направление и документацию.
Я предоставил все документы и доказательства, которые я нашел во время исследований и разработок.
4 ответа:
проведя целый день в Rnd и протестировав некоторые альтернативы, я нашел решение. На самом деле я нашел две альтернативы для той же проблемы, но я хотел бы предложить использование вариант 2 потому что это действительно очень легко по сравнению с Вариант 1.
на самом деле я нашел Вариант 1 С помощью TheLittleNaruto,AndroidHacker и некоторые другие разработчики & вариант 2 С помощью Хан так что спасибо всем.
Вариант 1
как нарисовать полигон свободного стиля на карте V2 (как мы можем сделать с картой V1) ? Возможно ли это в Map V2 ?
Да, это возможно, но вы не можете получить непосредственно
OnTouch()
&OnDraw()
на карте. Поэтому мы должны придумать какой-то другой способ достичь этого.есть ли какой-нибудь трюк или альтернативный способ добиться этого, если да, то как ?
Да, Google Map V2 не поддерживает
OnTouch()
илиOnDraw()
на карте с помощьюclass="com.google.android.gms.maps.SupportMapFragment"
поэтому мы должны планировать для пользовательского фрагмента.можно ли вернуть массив lat-long с сенсорным событием ?
да, если мы создадим любой пользовательский фрагмент карты и используем его, мы можем получить это Touch или перетащить событие на карте.
как я могу получить Lat-long base на экранных координатах на setOnDragListener ?
setOnDragListener
возвращает экранные координаты (x,y). Теперь для этого есть несколько методов для преобразования (x,y) до LatLng и они включают в себя проекция вместе с точка & 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: } });
как это работает ?
как у меня уже есть как уже упоминалось ранее, мы должны создать пользовательский корневой вид и используя это мы можем получить Touch или перетащить события на карте.
Шаг 1: Мы Создаем
MySupportMapFragment extends SupportMapFragment
и мы будем использовать его в качестве .xml-файл<fragment android:id="@+id/map" android:layout_width="fill_parent" android:layout_height="fill_parent" class="pkg_name.MySupportMapFragment" />
Шаг 2: Создайте
MapWrapperLayout extends FrameLayout
так что мы можем установить нажмите или перетащите слушателя внутри и встроить его вид с видом на карту. Итак, нам нужен один интерфейс, который мы будем использовать в Root_Map.javaMySupportMapFragment.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: } }); }}
до сюда я могу добраться LatLong на основе координаты экрана X,Y. Теперь я просто должен хранить его в массив. Этот массив будет используется для рисования на карте и, наконец, он будет выглядеть как полигон свободной формы.
я надеюсь, что это определенно поможет вам.
обновление:
вариант 2
как известно, каркас макета является прозрачным макетом, поэтому я достиг этого с помощью макета кадра. В этом случае нет необходимости создавать пользовательский фрагмент. Я только что использовал рама Макет как корневой макет. Так что в основном я получу Сенсорные События в корневом макете, и это вернет координаты экрана, как мы получили в пользовательском фрагменте ранее.
теперь я создал кнопку внутри"Free Draw". Поэтому, когда вы нажимаете на это, вы можете перемещать пальцы по карте и рисовать полигон свободной руки, и это отключит вашу карту, перемещающуюся на экране. При повторном нажатии на ту же кнопку, экран идет в идеале режим.
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
// кнопка изменит подвижное состояние карты
btn_draw_State.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Is_MAP_Moveable = !Is_MAP_Moveable; } });
Нажмите кнопку макета кадра и с помощью сделать некоторые задачи
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; } });
// нарисовать карту
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); }
тем не менее, теперь вы должны поддерживать свой список во время рисования, так что вы должны очистить ваши предыдущие данные списка.
зацени .. Я считаю, что вы способны показать Google Map v2
Проверьте" decodePoly "и" drawPath " метод в AsyncTask
основной Imphasis в "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);
полный класс для вашей справки ..
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 } }
надеюсь, что это помогает. Ура!
обновление
проверить это .. создание OnDragListener для Google Map V2 фрагмент
также проверьте это .. как нарисовать фигуру на фрагменте карты, коснувшись его с помощью google map V2
еще несколько ссылок .. как получить координаты экрана от маркера в google maps v2 android
таким образом, у нас есть некоторое решение для свободной руки рисовать на карте v2. Реализовать
GoogleMap.OnMarkerDragListener
в вашей деятельности карты . Он переопределит функцию 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)); } }
вы можете передать какой-то хак для свободной руки, как только пользователь коснется карты, вам нужно будет обнаружить эти координаты и передать их в onMarkerDrag . Как вам придется использовать информацию области для дальнейшего процесса. Для сенсорного события вы можете реализовать
GoogleMap.OnMapClickListener
и получить координаты от его параметра. Надеюсь, это поможет:)
это 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 ); } }
Ссылка:https://developers.google.com/maps/documentation/android/