在Android地图V2上是否可以添加折线箭头头部

8

如何使用Android Maps V2 API绘制带有箭头头部的折线(它表示方向)。在Android地图文档中,此选项不可用。是否有可能在折线上添加箭头?


在Android地图v2中,是否可以在折线上添加箭头?如何实现这个功能?有相关链接吗? - Ramprasad
你的意思是要追踪路线对吧!!! - Janmejoy
是的。我有多个位置,我想连接这些位置,并使用带箭头的折线显示为路线。 - Ramprasad
使用Android Maps v2 API,是否可以在折线上添加箭头? - Ramprasad
3个回答

13

这里有一个可行的示例,我使用Doug建议的相同概念进行开发,通过将JavaScript示例(http://econym.org.uk/gmap/example_arrows.htm)转换为Java代码。方便起见,它使用了来自Google Maps服务器的图像,但这些图像可以是您设计的图像,也可以从Web上抓取并在应用程序中本地存储。为了演示方便,我正在主线程上下载这些内容,但如果在实时应用程序中使用,请勿这样做!

然而,与JavaScript示例的关键区别在于,您必须将箭头头部图像投影到四倍大小的较大图像上,根据从A到B的方位计算出图像要平移的位置,并通过添加另一个带有更大图像的定位标记来在现有B标记上居中该图像作为图标。

首先添加您的折线:

PolylineOptions polylines = new PolylineOptions();

LatLng from = new LatLng(f.getLatitude(), f.getLongitude());
LatLng to = new LatLng(t.getLatitude(), t.getLongitude());

polylines.add(from, to).color(polyColor).width(2);

mMap.addPolyline(polylines);

DrawArrowHead(mMap, from, to);

然后添加箭头:

private final double degreesPerRadian = 180.0 / Math.PI;

private void DrawArrowHead(GoogleMap mMap, LatLng from, LatLng to){
    // obtain the bearing between the last two points
    double bearing = GetBearing(from, to);

    // round it to a multiple of 3 and cast out 120s
    double adjBearing = Math.round(bearing / 3) * 3;
    while (adjBearing >= 120) {
        adjBearing -= 120;
    }

    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy); 

    // Get the corresponding triangle marker from Google        
    URL url;
    Bitmap image = null;

    try {
        url = new URL("http://www.google.com/intl/en_ALL/mapfiles/dir_" + String.valueOf((int)adjBearing) + ".png");
        try {
            image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    if (image != null){

        // Anchor is ratio in range [0..1] so value of 0.5 on x and y will center the marker image on the lat/long
        float anchorX = 0.5f;
        float anchorY = 0.5f;

        int offsetX = 0;
        int offsetY = 0;

        // images are 24px x 24px
        // so transformed image will be 48px x 48px

        //315 range -- 22.5 either side of 315
        if (bearing >= 292.5 && bearing < 335.5){
            offsetX = 24;
            offsetY = 24;
        }
        //270 range
        else if (bearing >= 247.5 && bearing < 292.5){
            offsetX = 24;
            offsetY = 12;
        }
        //225 range
        else if (bearing >= 202.5 && bearing < 247.5){
            offsetX = 24;
            offsetY = 0;
        }
        //180 range
        else if (bearing >= 157.5 && bearing < 202.5){
            offsetX = 12;
            offsetY = 0;
        }
        //135 range
        else if (bearing >= 112.5 && bearing < 157.5){
            offsetX = 0;
            offsetY = 0;
        }
        //90 range
        else if (bearing >= 67.5 && bearing < 112.5){
            offsetX = 0;
            offsetY = 12;
        }
        //45 range
        else if (bearing >= 22.5 && bearing < 67.5){
            offsetX = 0;
            offsetY = 24;
        }
        //0 range - 335.5 - 22.5
        else {
            offsetX = 12;
            offsetY = 24;
        }

        Bitmap wideBmp;
        Canvas wideBmpCanvas;
        Rect src, dest;

        // Create larger bitmap 4 times the size of arrow head image
        wideBmp = Bitmap.createBitmap(image.getWidth() * 2, image.getHeight() * 2, image.getConfig());

        wideBmpCanvas = new Canvas(wideBmp); 

        src = new Rect(0, 0, image.getWidth(), image.getHeight());
        dest = new Rect(src); 
        dest.offset(offsetX, offsetY); 

        wideBmpCanvas.drawBitmap(image, src, dest, null);

        mMap.addMarker(new MarkerOptions()
        .position(to)
        .icon(BitmapDescriptorFactory.fromBitmap(wideBmp))
        .anchor(anchorX, anchorY));
    }
}

private double GetBearing(LatLng from, LatLng to){
    double lat1 = from.latitude * Math.PI / 180.0;
    double lon1 = from.longitude * Math.PI / 180.0;
    double lat2 = to.latitude * Math.PI / 180.0;
    double lon2 = to.longitude * Math.PI / 180.0;

    // Compute the angle.
    double angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );

    if (angle < 0.0)
        angle += Math.PI * 2.0;

    // And convert result to degrees.
    angle = angle * degreesPerRadian;

    return angle;
}

如果您已经下载了图像并将其放在应用程序中,您可以尝试使用以下代码:int identifier = getResources().getIdentifier("dir_" + String.valueOf((int)adjBearing), "drawable", getActivity().getPackageName()); Bitmap image = BitmapFactory.decodeResource(getResources(), identifier); - Breeno
另外,如果您要从网络上抓取图像并将它们放入drawable文件夹中,请确保将它们放入drawable-nodpi文件夹中,以便它们不会因屏幕密度而被缩放! - Breeno
1
还有...禁用地图手势旋转,因为箭头不会随着地图旋转! Map.getUiSettings().setRotateGesturesEnabled(false); - Breeno
1
我觉得有义务把-1放进去,因为在主线程上进行网络请求是没有借口的。此外,输入流没有关闭。 - Display Name

4
截至 2017年2月15日发布的Android Maps API v2,您现在可以在Android Maps API v2上为折线末端添加自定义线帽, 它们可以是箭头。
线帽文档中可知:

The following snippet specifies a custom bitmap for the end cap:

mPolyline.setEndCap(
        new CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.arrow),
                16));

When you use a custom bitmap, you should specify a reference stroke width in pixels. The API scales the bitmap accordingly. The reference stroke width is the stroke width that you used when designing the bitmap image for the cap, at the original dimension of the image. The default reference stroke width is 10 pixels. Hint: To determine the reference stroke width, open your bitmap image at 100% zoom in an image editor, and plot the desired width of the line stroke relative to the image.

If you use BitmapDescriptorFactory.fromResource() to create the bitmap, make sure you use a density-independent resource (nodpi).

谷歌的相关问题解决帖子在这里中说:
我们增加了自定义位图的功能,用于定制折线的起点和终点。使用此功能,您将能够在折线上添加箭头。请参阅Shapes Guide中有关Line Caps的信息:https://developers.google.com/maps/documentation/android-api/shapes#line_caps。请参阅新的Polylines and Polygons教程中的示例:https://developers.google.com/maps/documentation/android-api/polygon-tutorial#add_custom_styling_to_your_polyline。请查看发布说明:https://developers.google.com/maps/documentation/android-api/releases#february_15_2017。请查看博客文章:https://maps-apis.googleblog.com/2017/02/styling-and-custom-data-for-polylines.html

你好 能给个箭头图像的例子吗? 我对它的方向感兴趣,是N、S、W还是E?例如。 - Vlad

1
我没有尝试过这个方法,但我认为可以使用标记完成。您需要创建一系列小箭头,例如20个,每个箭头指向不同的方向,如18度、36度、54度等。然后,在构建折线时或者可能更好的是,在折线构建完成后作为一个单独的过程,按照所需间隔遍历所有坐标,并在每个选择的点上使用locationn.getbearing获取方位角,并从该方位角确定要使用哪个方向的箭头作为标记,并在该点放置相应的标记。

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