Как нарисовать свободный полигон в карте Google V2 в Android?
Я хочу нарисовать a Free Hand Polygon on the Map in Google Map V2
.
Эта задача была возможна с помощью Overlay
Map V1, но карта Google удалила этот класс из V2. (Для этого Google Map V2 удаляет класс Overlay).
Хороший пример для Google Map V1 для рисования свободного полигона стиля.
В Map V2 мы можем программно сделать полигон с помощью Официального документа Google, но что должен делать пользователь? Я нашел Непонятный ответ для карты V2
Я начал с простой карты Google и нарисовал полигон, чтобы сделать это программно, и он работает правильно, но теперь я ищу, как пользователь может рисовать? Я не хочу рисовать на основе маркера на многоугольнике.
// 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.
Некоторые вопросы
- Как нарисовать многогранный многоугольник в Map V2 (как мы можем сделать с Map V1)?
- Есть ли какой-либо трюк или альтернатива для достижения этого? Если да, то как?
- Можем ли мы получить событие касания на карте и нарисовать полигон?
- Возможно ли это в Map V2?
- Возможно ли с событием касания, которое возвращает массив lat-long?
- Как я могу получить Lat-long на основе экранных координат на
setOnDragListener
?
В каждой новой версии есть что-то дополнительное по сравнению со старым, поэтому я ожидаю, что я тоже смогу добиться того же самого в Map v2.
Я не прошу дать мне пример кода или оставить свой код, просто правильное руководство и документацию.
Я представил все документы и доказательства, которые я нашел во время исследований и разработок.
Ответы
Ответ 1
Проведя целый день в Rnd и тестируя некоторые альтернативы, я нашел решение. На самом деле я нашел две альтернативы для одной и той же проблемы, но я хотел бы предложить использовать Альтернатива 2, потому что это действительно очень легко по сравнению с Альтернатива 1.
На самом деле я нашел Альтернативу 1 с помощью TheLittleNaruto, AndroidHacker и некоторые другие разработчики и Альтернатива 2 с помощью Khan, поэтому благодаря всем.
Альтернатива 1
Как рисовать свободный многоугольник стиля в Map V2 (как мы можем сделать с Map 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, и они включают Projection вместе с 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:
}
});
Как это работает?
Как я уже упоминал ранее, мы должны создать пользовательский корневой вид и используя это, мы можем получить 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
, чтобы мы могли установить внутри Touch или Drag listener внутри и встроить его представление с видом карты. Итак, нам нужен один интерфейс, который мы будем использовать в 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:
}
});
}}
Ссылка Link1, Ссылка2
До сих пор я могу получить LatLong на основе X, Y экранных координат. Теперь мне просто нужно сохранить его в Массив. Этот массив будет использоваться для рисования на карте и, наконец, он будет выглядеть как многоугольник свободной формы.
![enter image description here]()
Надеюсь, это определенно поможет вам.
Update:
Альтернатива 2
Как известно, Рамка макета - это прозрачный макет, поэтому я достиг этого с помощью макета кадра.
В этом случае нет необходимости создавать пользовательский фрагмент. Я только что использовал Макет кадра как корневой макет. Таким образом, в основном я получаю Touch Events в корневом макете, и это вернет координаты экрана, поскольку мы получили ранее выполненный фрагмент.
Теперь я создал кнопку внутри "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);
}
Тем не менее, теперь вам нужно сохранить свой список во время рисования, поэтому вам нужно очистить предыдущие данные списка.
Ответ 2
Проверьте это. Я считаю, что U способны показывать Google Map v2
Проверьте метод decodePoly и drawPath в AsyncTask
Основное значение в "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
}
}
Надеюсь, это поможет. Ура!
UPDATE
ознакомьтесь с этим. Создание OnDragListener для Google Map v2 Fragment
Также проверьте это.
Как нарисовать фигуру на фрагменте карты, коснувшись ее с помощью карты Google V2
Дополнительная информация.. Как получить координаты экрана с маркера в google maps v2 android
Ответ 3
Итак, у нас есть некоторое решение для розыгрыша свободной руки на карте v2.
Внесите GoogleMap.OnMarkerDragListener
в свою активность на карте. Он переопределит функцию onMarkerDrag.
@Override
public void onMarkerDrag(Marker marker) {
//add the marker 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
и получить координаты из этого параметра.
Надеюсь, это поможет:)
Ответ 4
это 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/