Google Maps Android API v2中带文本的地图标记

21

我写了这篇文章,但它是针对已弃用的Google Maps API的。

http://tech.truliablog.com/2012/02/23/custom-map-markers-for-android-google-maps/

在新的API中,我无法找到一种简单的方法来实现这一点。事实上,我根本无法做到。

基本上,我想在地图上将TextView作为标记,并使用9Patch drawable作为文本的背景。Trulia仍然在其当前应用程序中使用新的API v2进行此操作。您可以在此处查看。

Trulia current app

我该如何做到这一点?


2
请使用信息窗口。https://developers.google.com/maps/documentation/android/marker - Raghunandan
4
你看过上面的图片吗?这些小标记是否看起来像信息窗口? - tasomaniac
这对我来说看起来像信息窗口。如果不是,你在寻找什么?另外,你有检查过发布的链接吗? - Raghunandan
1
不,它们是标记。当您单击它们时,它们会显示信息窗口。 - tasomaniac
1
请查看所发布的链接,其中包含有关标记和信息窗口的详细信息。 - Raghunandan
7个回答

40

17

使用谷歌提供的这个有用的库很容易实现。

IconGenerator icg = new IconGenerator(this);
icg.setColor(Color.GREEN); // green background 
icg.setTextAppearance(R.style.BlackText); // black text 
Bitmap bm = icg.makeIcon("200 mi");

在 style.xml 中

<style name="BlackText" parent="TextDefault">
    <item name="android:textColor">@color/black</item>
</style>

http://googlemaps.github.io/android-maps-utils/javadoc/

http://googlemaps.github.io/android-maps-utils/

https://github.com/googlemaps/android-maps-utils

你可以从这个链接中设置你的项目中的上述链接。


让我开心了一整天。非常感谢。 - Itoun

6
据我所知,谷歌地图API V2目前不支持此功能。但是,您可以动态创建标记的位图,并写入想要显示的值。不过,如果您有大量的标记,可能会出现性能问题。
Canvas canvas = new Canvas(bitmap);
canvas.drawText("Your text", textXOffset, textYOffset, mPictoPaint);
MarkerOptions options = new MarkerOptions().position([…]).icon(BitmapDescriptorFactory.fromBitmap(bitmapResult));
Marker newMarker = map.addMarker(options);

请注意,bitmap需要可变。此外,您需要按照自己的需求缩放基本图像(可能使用9.patch)。

我已经尝试了几个小时做类似的事情。我已经完成了这个任务,但是我无法将9Patch可绘制对象添加到背景中。 - tasomaniac
这个会有帮助吗?虽然它可能不是可变的,所以可能需要进行一些额外的处理。 - Nerkatel
好的,这个链接也很有帮助,但是那里有x和y变量。在绘制9patch可绘制对象之前,我不知道实际文本的高度。我该如何利用最后一个链接中的代码并使用drawText()函数? - tasomaniac
你的文本是单行还是多行?前者比较容易,你可以使用 Paint.measureText 来获取文本显示时所占用的大小,并推断出位图的大小(加上额外的填充)。多行的方案相对麻烦,如果可以的话,建议避免使用。对于单行版本,另一种解决方案是使用 StaticLayout,再次获取文本在屏幕上所占用的大小。 - Nerkatel
当然,这是一种最优的方法,但也可以使用“视图”来实现。 - MaciejGórski
这实际上只是一行代码。感谢您的答案。我本来就要试试,但@MaciejGórski的答案非常好。它可以直接使用。我之前搜索了类似的东西,但没找到。 - tasomaniac

5

尽管这个问题有点老,但我还是在这里发布我的答案,以便帮助其他人。

以上的解决方案都对我没有用,因为:

  • 我的应用程序已经有了自定义标记图标

  • 我的应用程序显示可能有数千个不同的标记标题,因此在内存中创建这么多图像会导致性能问题

  • 随着标记图标变得越来越大,地图很快就变得不可读

  • 如果空间不够,我希望标题只在有空间的情况下显示,可能会被隐藏

我在互联网上找不到解决方案,所以我挽起袖子做出了这个库,它解决了我的问题,希望它也能帮助其他人:

https://github.com/androidseb/android-google-maps-floating-marker-titles

以下是它的预览:

preview


2

参考谷歌的示例代码

IconGenerator iconFactory = new IconGenerator(this);    
        iconFactory.setColor(Color.CYAN);
        addIcon(mMap, iconFactory, "Custom color", new LatLng(-33.9360, 151.2070));

在此处添加addIcon()方法:

private void addIcon(GoogleMap googleMap, IconGenerator iconFactory, CharSequence text, LatLng position) {
        MarkerOptions markerOptions = new MarkerOptions().
                icon(BitmapDescriptorFactory.fromBitmap(iconFactory.makeIcon(text))).
                position(position).
                anchor(iconFactory.getAnchorU(), iconFactory.getAnchorV());

        googleMap.addMarker(markerOptions);
    }

0
一个可行的解决方案。 对于MarkerOptions对象:
        markerOptions = new MarkerOptions()
                .position(posPrm)
                .title("" + order_id)
                .snippet(sLcl2)
                icon(giveMeBitmapDescriptor(mapsActivity,R.drawable.route_marker))
        ;

还有这个方法:

private BitmapDescriptor giveMeBitmapDescriptor(Context context,
        int iconPrm) {
    Drawable background = ContextCompat.getDrawable(context, iconPrm);
    background.setBounds(0, 0, background.getIntrinsicWidth(), background.getIntrinsicHeight());
    Bitmap bitmap = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    background.draw(canvas);
    Rect r = new Rect();
    canvas.getClipBounds(r);
    int cHeight = r.height();
    int cWidth = r.width();
    Paint paint = new Paint();
    paint.setTextAlign(Paint.Align.LEFT);
    paint.getTextBounds("text", 0, "text".length(), r);
    float x = cWidth / 2f - r.width() / 2f - r.left;
    float y = cHeight / 2f + r.height() / 2f - r.bottom;
    canvas.drawText("text", x, y, paint);
    return BitmapDescriptorFactory.fromBitmap(bitmap);
}

此操作应在 UI 线程中运行,否则它不会声明任何内容并绘制没有文本的图标。


0

如果您使用Clusters,则行为会略有不同。

参考https://medium.com/@yilmazvolkan/custom-map-marker-8b136212d766和这里,我写了这样的内容。

styles.xml:

<!-- Google Maps marker -->
<style name="MarkerText">
    <item name="android:textSize">12sp</item>
    <item name="android:textColor">#f0f0f0</item>
</style>

marker_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >

    <solid android:color="#3232a0" />
    <corners android:radius="18dp" />
</shape>

片段:

private var clusterManager: ClusterManager<SomeClusterItem>? = null
private var clusterRenderer: MarkerClusterRenderer<SomeClusterItem>? = null
private var unselectedBitmap: BitmapDescriptor? = null
private var iconGenerator: IconGenerator? = null
private var selectedItem: SomeClusterItem? = null

override fun onMapReady(googleMap: GoogleMap) {
    this.googleMap = googleMap
    ...

    unselectedBitmap =
        BitmapUtils.bitmapDescriptorFromVector(context!!, R.drawable.unselected_item)

    // Create a text marker background.
    iconGenerator = IconGenerator(context!!)
    iconGenerator!!.setTextAppearance(R.style.MarkerText)
    val markerBackground = ContextCompat.getDrawable(context!!, R.drawable.marker_bg)
    iconGenerator!!.setBackground(markerBackground)

    clusterManager = ClusterManager(context!!, googleMap)
    clusterRenderer = MarkerClusterRenderer(context!!, googleMap, clusterManager!!,
        unselectedBitmap!!)
    clusterManager!!.renderer = clusterRenderer

    ...
    // Create a list of markers.
    val boundsBuilder = LatLngBounds.Builder()
    ...

    // Show clusters and markers.
    clusterManager!!.cluster()

    clusterManager!!.setOnClusterItemClickListener { item ->
        // Deselect selected marker.
        // See https://dev59.com/PYvda4cB1Zd3GeqPgvsm#53829888.
        if (selectedItem != null) {
            deselectMarker(selectedItem)
        }
        selectedItem = item
        selectMarker(selectedItem!!, iconGenerator)
        // Show info window. See GoogleMap.InfoWindowAdapter.
        false
    }
    clusterManager!!.setOnClusterClickListener {
        deselectMarker(selectedItem)
        true
    }


private fun selectMarker(item: SomeClusterItem,
                         iconGenerator: IconGenerator) {
    // Generate a text marker.
    val icon = iconGenerator.makeIcon(item.title)
    val bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(icon)
    clusterRenderer?.getMarker(item)?.setIcon(bitmapDescriptor)
}

private fun deselectMarker(item: SomeClusterItem?) =
    clusterRenderer?.getMarker(item)?.setIcon(unselectedBitmap)

然后你会看到这些图片(所有项目都未被选中,一个项目被选中)。

enter image description here enter image description here

请注意InfoWindow已显示。如需自定义信息窗口,请参见https://dev59.com/WmYr5IYBdhLWcg3wKHIp#59952706
要删除信息窗口,只需在适当的方法中返回true(请参见Hide markers info window in android google maps API v2)。
clusterManager!!.setOnClusterItemClickListener { item ->
    ...
    true
}

enter image description here


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