Google Maps Android API v2中的折线触摸检测

13

我想在使用Google Maps V2 Android API显示的折线上实现一个touchListener

缩放级别: CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(lat_Lng, 5);

我尝试了以下折线触摸代码:

boolean onpoly = false;
            for (Polyline polyline : mPolylines) {
                for (LatLng polyCoords : polyline.getPoints()) {
                    float[] results = new float[1];

                    Location.distanceBetween(points.latitude, points.longitude, polyCoords.latitude, polyCoords.longitude, results);

                    if (results[0] < 100 ) {
                        onpoly = true;

                        Marker mark = map.addMarker(new MarkerOptions().position(points).title("AddEvent")

                        .snippet("" + addressaddexpense).icon(BitmapDescriptorFactory.fromResource(R.drawable.addicon)));

                        UtilsClass.dropPinEffect(mark);
                    }// end if..
                } // end for loop
            }// end for loop

            if (onpoly == true) {
                Toast.makeText(getActivity(), "Poly line detected", Toast.LENGTH_SHORT).show();
            }// end if

它可以工作但不是非常完美。除非我放大地图,否则它将无法检测到触摸事件,有时我不得不在缩放之前点击地图超过5次才能实现检测。

然后我将上述的if条件从if (results[0] < 100 )更改为if (results[0] < 150 * (22 - map.getCameraPosition().zoom)),功能得到改善,但仍然不总是有效。

注意:我希望在任何缩放级别下都能检测到折线触摸。


我有以下问题需要您提供比我目前的回答更好的答案:
  1. 发布的代码位于何处?是在onMapClickListener中吗?还是在dispatchTouchEvent中?还是其他地方?
  2. 当您说要检测折线触摸时,您是指单击该线还是还想启用滑动或其他触摸手势?
- Royi Benyossef
我在 onMapLongClickListener 中使用了这段代码。 - harikrishnan
好的,请尝试使用onMapClickListener(长按实际上是设计用来执行您所描述的操作的,即仅在项目上进行长时间单击而没有移动后才被调用),并查看我的答案 :) - Royi Benyossef
4个回答

1
尝试这个。
    final List<LatLng> latLngList; // Extract polyline coordinates and put them on this list
    private GoogleMap map;

for(int i = 0; i < latLngList.size(); i++){
                MarkerOptions mar = new MarkerOptions();
                    mar.position(new LatLng(latLngList.get(i).latitude, latLngList.get(i).longitude)).icon(BitmapDescriptorFactory.fromResource(R.drawable.trasparent_image)); //this image should be very small in size and transparent
                    map.addMarker(mar);
            }

            map.setOnMarkerClickListener(new OnMarkerClickListener() {

                @Override
                public boolean onMarkerClick(Marker arg0) {
                    for(int i = 0; i < latLngList.size(); i++){
                    if(latLngList.get(i).latitude == arg0.getPosition().latitude && latLngList.get(i).longitude == arg0.getPosition().longitude){
                        Toast.makeText(MainActivity.this, "PolyLineClick ", Toast.LENGTH_SHORT).show();
                        break;
                    }
                }
                    return false;
                }
            });

只需要一个透明图像,并用标记替换它 - Abhishek
让我检查一下这个方法。 - harikrishnan
你的方法是正确的,但是这里的折线坐标列表大小将超过五万(50k)。而且,ArrayList 内存溢出错误已经出现了。我无法将所有折线值存储在一个列表中。 - harikrishnan
我建议不要保留平滑路径的所有坐标,只需存储步骤数组的坐标即可,这样也可以完美地工作;但是在低缩放级别下,它可能无法消耗点击,但在更高的缩放级别下,这并不会有任何影响。 - Abhishek
我不理解如何将坐标存储在步骤数组中。我知道普通的ArrayList,但不知道如何操作。 - harikrishnan
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - harikrishnan

0

在我的评论中的问题得到回答之前,我想尝试通过建议使用第三方库android-maps-utils来使它们变得多余。

要做我认为你可能正在尝试做的事情,只需集成该库并使用以下行:PolyUtil.isLocationOnPath(point, polyline.getPoints(), isGeodesic, tolerance);

如需更多信息,您还可以查看此thread,似乎也适用。

祝好运。


我尝试了这个royiby。但是,这两个参数isGeodesic和tolerance出现了错误。我在哪里可以获取这些参数的值..我也在谷歌上搜索过并得到了以上那行代码。 - harikrishnan
这两个参数是关于您检测偏好的,您尝试了哪些值? - Royi Benyossef
isGeodesic是一个布尔值 - 因为你正在检测一条线,我建议尝试true和false两种情况,看哪个效果最好。 tolerance也是一个参数,关于你想要多轻的触摸才能触发它,所以我建议从0开始测试,这表示没有容差,所以最轻微的触摸就会触发它。 在你让它运行后,尝试微调它,使其变得好用但不会很烦人(希望任何颠簸都不会触发它)。 - Royi Benyossef
我尝试了这个代码:roy..PolyUtil.isLocationOnPath(points, mPolylines, true, 0.0);但是,我得到了这个错误.....在PolyUtil类型中,方法isLocationOnPath(LatLng, List<LatLng>, boolean, double)不适用于参数(LatLng, List<Polyline>, boolean, double)。 - harikrishnan
map.setOnMapClickListener(new GoogleMap.OnMapClickListener() { @Override public void onMapClick(LatLng points) { PolyUtil.isLocationOnPath(points, mPolylines, true, 0.0) ; } }); - harikrishnan
显示剩余2条评论

0

我认为你的方法是正确的。唯一失败的是距离检查。这是因为触摸和缩放级别:

当你点击屏幕时,传递给应用程序的屏幕点是与屏幕接触的手指表面的中心。这意味着,即使看起来你的手指正好在PolyLine上方,它也可能会偏移几个像素...

现在是缩放级别的时间,根据其当前值,传递给应用程序和PolyLine之间的距离可以变化很大。

结果,if子句失败了,你必须多次点击,直到有些点击足够靠近PolyLine。当然,随着缩放级别的提高,情况会变得更好。

你应该像你编辑的代码一样包含缩放级别,但是还要加上一些额外的内容:
检查您允许进入if的“delta”,但在最大缩放级别上。它应该是一个小值。然后,您只需将其乘以当前缩放级别,并计算此增量的变化。在您的if比较中使用此缩放相关值。
为了增强它,您可以进行更复杂的计算,并从像素距离开始获取此增量。假设,50像素或更少的点击到PolyLine将被接受。在最大缩放级别上计算这个像素距离的米数,并将其乘以当前缩放级别...
为了进一步提高它,您可以使这个像素距离依赖于屏幕分辨率和密度。

在这里,您可以找到如何将屏幕像素计算为米的方法:https://dev59.com/DWvXa4cB1Zd3GeqPJn6k#13635952


0

我以下面的方式实现了类似的功能:

  1. 使用map.getProjection().toScreenLocation()将所有位置转换为屏幕坐标。
  2. 使用标准的距离公式来确定点到点(或从点到线段,如果您想要检测线段上的点击)的距离。如果此距离小于某个阈值,则会检测到点击。

关键在于使用地图投影获取屏幕坐标。这样决策就取决于屏幕上的实际像素距离,而不是缩放级别。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接