我想在Google Map V2的地图上画一个徒手多边形。
这项任务可以在地图V1中完成,但Google地图已经从V2中删除了该类。(根据此Google Map V2具有删除覆盖类)。
Google Map V1绘制自由风格多边形的好例子。
在Map V2中,我们可以借助Google官方文档以编程方式绘制多边形,但用户应该怎么做?我发现Map V2的答案不清楚
我从简单的谷歌地图开始
// 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 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,并从其参数中获取坐标。希望这会有所帮助:)
看看这个。。我相信你有能力展示谷歌地图v2
查看AsyncTask中的“DecdePoly”和“drapath”方法
主要影响因素在“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
}
}
希望有帮助。干杯!
更新
看看这个。。为Google Map v2片段创建OnDragListener
也检查一下这个。。如何使用google map V2通过触摸在地图片段上绘制形状
更多参考...如何从谷歌地图v2 android中的标记获取屏幕坐标
在Rnd呆了一整天并测试了一些替代品之后,我找到了一个解决方案。事实上,我已经为同一问题找到了两个备选方案,但我建议使用备选方案2,因为与备选方案1相比,这真的很容易。
事实上,我在TheLittleNaruto、AndroidHacker和其他一些开发人员的帮助下找到了替代方案1
备选方案1
如何在Map V2中绘制自由风格的多边形(就像我们可以在Map V1中做的那样)?在Map V2中可行吗?
是的,这是可行的,但您无法直接获取
是否有任何技巧或替代方法来实现这一目标,如果有,如何实现?
是的,Google Map V2不支持使用地图上的OnTouch()或OnDraw(),因此我们必须计划一个自定义片段。
可以用触摸事件返回lat-long数组吗?
是的,如果我们创建任何自定义地图片段并使用它,我们可以在地图上获得该触摸或拖动事件。
如何在setOnDragListener上获得基于屏幕坐标的Lat long?
setOnDragListener
将返回屏幕坐标(x, y)。现在,有一些技术可以将(x, y)转换为LatLng,它们包括投影和Point
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:
}
});
它是如何工作的?
正如我之前提到的,我们必须创建一个自定义根视图,并使用它可以在地图上触摸或拖动事件。
步骤1:我们创建MySupportMapFragment扩展SupportMapFragment,并将其用作我们的。xml文件
<fragment
android:id="@+id/map"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="pkg_name.MySupportMapFragment" />
步骤2:创建一个MapWrapperLayout扩展了FrameLayout,这样我们就可以在其中设置一个触摸或拖动侦听器,并用map view嵌入其视图。因此,我们需要一个将在Root\u映射中使用的接口。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\u映射。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、Link2
到目前为止,我能够根据X,Y屏幕坐标获得LatLong。现在我只需要将其存储在数组中。该数组将用于在地图上绘制,最后它将看起来像一个自由形状的多边形。
我希望这一定会对你有所帮助。
备选方案2
正如我们所知,框架布局是一种透明布局,所以我使用框架布局实现了这一点。在这种情况下,不需要创建自定义片段。我刚刚使用框架布局作为根布局。因此,基本上我将在根布局中获取触摸事件,并返回屏幕坐标,正如我们在前面的自定义片段中所获得的那样。
现在,我在“自由抽签”中创建了一个按钮。因此,当您单击该按钮时,您可以在地图上移动手指并绘制一个徒手多边形,这将禁用您的地图在屏幕上的移动。当您再次单击同一按钮时,屏幕将进入理想模式。
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\u映射。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);
}
然而,现在必须在绘制时维护列表,因此必须清除以前的列表数据。
问题内容: 我在本教程中使用了六边形代码,并创建了一个createHex类(我应该发布代码吗?)。链接的网页已使用以下代码通过createHex中的数学运算实际绘制六边形: 我遇到的问题是Android没有包含所有必需方法的Graphics类。我在android文档上做了大约一个半小时的钓鱼,而我发现最接近的东西是Path类,但是它没有我需要的方法。我想在顶部的链接文章中使用六边形代码,但找不到等
我需要在Mapbox Android SDK地图上绘制一个带孔的GeoJSON多边形。 正如GeoJSON规范所说, 对于类型“多边形”,“坐标”成员必须是线性环坐标数组的数组。对于有多个环的多边形,第一个必须是外环,其他必须是内环或孔。 在手册Mapbox JS和Mapbox GL JS中,加载GeoJSONs由库本身处理。从这把小提琴中可以看出,lib考虑了内环,因此正确地绘制了孔。 当我查看
问题内容: 我需要知道如何在画布上绘制多边形。不使用jQuery或类似的东西。 问题答案: 使用和创建一个路径:
问题内容: 我正在尝试绘制这样的多边形: 我希望得到以下输出: 为什么仍然是零?还有另一种方法将填充的多边形绘制到数组吗? 问题答案: 这是一个奇怪的结果。我发现,如果您颠倒了点的顺序,则会绘制出完整的图形。换一种说法: 这是一个测试程序: 例子:
假设我有三个锚,来自阿拉片段的命中结果。 锚定=命中结果。createAnchor(); 如何使用Sceneform绘制三角形并应用自定义纹理?
问题内容: 我刚接触Android,并且一直在研究Canvas。我正在尝试绘制箭头,但是在绘制轴时运气不好,没有一个箭头在起作用。 我进行了一些搜索,找到一个Java示例,但是Android没有or 。 现在,我的代码如下所示(箭头看上去完全不像箭头): 我查看了以下线程以获取指导: * http://www.java-forums.org/awt-swing/6241-how-u-rotate-