标记

请选择平台: Android iOS JavaScript

标记用于指示地图上的单个位置。您可以对标记进行自定义,比如更改其默认颜色,或者将标记图标替换成自定义的图片。信息窗口可提供有关标记的更多背景信息。

代码示例

GitHub 上的 ApiDemos 代码库包含一个展示各种标记功能的示例:

Kotlin

Java

简介

标记用于标识地图上的位置。默认标记使用与 Google 地图外观和风格一致的标准图标。可以通过 API 更改图标的颜色、图像或锚点。标记是 Marker 类型的对象,可通过 GoogleMap.addMarker(markerOptions) 方法添加到地图中。

标记的设计支持互动。默认情况下,它们会接收 click 事件,并且常与事件监听器结合使用来调出信息窗口。通过将标记的 draggable 属性设置为 true,用户即可更改标记的位置。长按标记即可激活移动标记的功能。

默认情况下,当用户点按标记时,地图工具栏会显示在地图右下角,方便用户快速访问 Google 地图移动应用。您可以停用工具栏。如需了解详情,请参阅控件指南

标记使用入门

本集 Maps Live 介绍了利用 Maps SDK for Android 向地图添加标记的基础知识。

添加标记

以下示例展示了如何向地图添加标记。该标记在 -33.852,151.211 坐标处(澳大利亚悉尼)创建;当用户点击它时,它会在信息窗口中显示字符串“Marker in Sydney”(悉尼的标记)。

Kotlin



override fun onMapReady(googleMap: GoogleMap) {
    // Add a marker in Sydney, Australia,
    // and move the map's camera to the same location.
    val sydney = LatLng(-33.852, 151.211)
    googleMap.addMarker(
        MarkerOptions()
            .position(sydney)
            .title("Marker in Sydney")
    )
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
}

      

Java


@Override
public void onMapReady(GoogleMap googleMap) {
    // Add a marker in Sydney, Australia,
    // and move the map's camera to the same location.
    LatLng sydney = new LatLng(-33.852, 151.211);
    googleMap.addMarker(new MarkerOptions()
        .position(sydney)
        .title("Marker in Sydney"));
    googleMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}

      

显示与标记有关的更多信息

常见的要求是,当用户点按地图上的某个标记时,需显示有关相应地点或位置的更多信息。请参阅有关信息窗口的指南。

将数据与标记关联

您可以使用 Marker.setTag() 将任意数据对象存储在标记中,并可使用 Marker.getTag() 检索该数据对象。以下示例展示了如何使用标签统计标记的点击次数:

Kotlin



/**
 * A demo class that stores and retrieves data objects with each marker.
 */
class MarkerDemoActivity : AppCompatActivity(),
    OnMarkerClickListener, OnMapReadyCallback {
    private val PERTH = LatLng(-31.952854, 115.857342)
    private val SYDNEY = LatLng(-33.87365, 151.20689)
    private val BRISBANE = LatLng(-27.47093, 153.0235)

    private var markerPerth: Marker? = null
    private var markerSydney: Marker? = null
    private var markerBrisbane: Marker? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_markers)
        val mapFragment =
            supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
        mapFragment!!.getMapAsync(this)
    }

    /** Called when the map is ready.  */
    override fun onMapReady(map: GoogleMap) {
        // Add some markers to the map, and add a data object to each marker.
        markerPerth = map.addMarker(
            MarkerOptions()
                .position(PERTH)
                .title("Perth")
        )
        markerPerth?.tag = 0
        markerSydney = map.addMarker(
            MarkerOptions()
                .position(SYDNEY)
                .title("Sydney")
        )
        markerSydney?.tag = 0
        markerBrisbane = map.addMarker(
            MarkerOptions()
                .position(BRISBANE)
                .title("Brisbane")
        )
        markerBrisbane?.tag = 0

        // Set a listener for marker click.
        map.setOnMarkerClickListener(this)
    }

    /** Called when the user clicks a marker.  */
    override fun onMarkerClick(marker: Marker): Boolean {

        // Retrieve the data from the marker.
        val clickCount = marker.tag as? Int

        // Check if a click count was set, then display the click count.
        clickCount?.let {
            val newClickCount = it + 1
            marker.tag = newClickCount
            Toast.makeText(
                this,
                "${marker.title} has been clicked $newClickCount times.",
                Toast.LENGTH_SHORT
            ).show()
        }

        // Return false to indicate that we have not consumed the event and that we wish
        // for the default behavior to occur (which is for the camera to move such that the
        // marker is centered and for the marker's info window to open, if it has one).
        return false
    }
}

      

Java


/**
 * A demo class that stores and retrieves data objects with each marker.
 */
public class MarkerDemoActivity extends AppCompatActivity implements
    GoogleMap.OnMarkerClickListener,
    OnMapReadyCallback {

    private final LatLng PERTH = new LatLng(-31.952854, 115.857342);
    private final LatLng SYDNEY = new LatLng(-33.87365, 151.20689);
    private final LatLng BRISBANE = new LatLng(-27.47093, 153.0235);

    private Marker markerPerth;
    private Marker markerSydney;
    private Marker markerBrisbane;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_markers);
        SupportMapFragment mapFragment =
            (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    /** Called when the map is ready. */
    @Override
    public void onMapReady(GoogleMap map) {
        // Add some markers to the map, and add a data object to each marker.
        markerPerth = map.addMarker(new MarkerOptions()
            .position(PERTH)
            .title("Perth"));
        markerPerth.setTag(0);

        markerSydney = map.addMarker(new MarkerOptions()
            .position(SYDNEY)
            .title("Sydney"));
        markerSydney.setTag(0);

        markerBrisbane = map.addMarker(new MarkerOptions()
            .position(BRISBANE)
            .title("Brisbane"));
        markerBrisbane.setTag(0);

        // Set a listener for marker click.
        map.setOnMarkerClickListener(this);
    }

    /** Called when the user clicks a marker. */
    @Override
    public boolean onMarkerClick(final Marker marker) {

        // Retrieve the data from the marker.
        Integer clickCount = (Integer) marker.getTag();

        // Check if a click count was set, then display the click count.
        if (clickCount != null) {
            clickCount = clickCount + 1;
            marker.setTag(clickCount);
            Toast.makeText(this,
                marker.getTitle() +
                    " has been clicked " + clickCount + " times.",
                Toast.LENGTH_SHORT).show();
        }

        // Return false to indicate that we have not consumed the event and that we wish
        // for the default behavior to occur (which is for the camera to move such that the
        // marker is centered and for the marker's info window to open, if it has one).
        return false;
    }
}

      

以下示例介绍了可使用标记存储和检索数据的情形:

  • 您的应用可能需要使用不同类型的标记,并且您希望在用户点击这些标记时分别以不同的方式处理它们。为做到这一点,您可以在标记中存储一个 String,用于指示标记的类型。
  • 您可能会与包含唯一记录标识符的系统对接,其中每个标记对应该系统中的特定记录。
  • 标记数据可能会指示在确定标记的 Z-index 时要使用的优先级。

使标记可拖动

将标记添加到地图中后,只要标记的 draggable 属性设为 true,您就可以调整标记的位置。长按标记即可激活拖动功能。手指离开屏幕后,标记会留在手指离开屏幕前的位置。

默认情况下,标记是不可以拖动的。您必须明确将标记设置为可拖动;为此,可在将标记添加到地图前使用 MarkerOptions.draggable(boolean),或者在添加到地图后使用 Marker.setDraggable(boolean)。可以按标记拖动事件中的说明监听标记上的拖动事件。

下面这段代码可在澳大利亚珀斯的位置处添加一个可拖动标记。

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .draggable(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .draggable(true));

      

自定义标记

这段视频介绍了如何利用标记直观展示地图上的位置。

您可以为标记设置自定义图像,以替换默认图标。设置图标时,您需要设置一些属性来调整标记的视觉行为。

可通过下列属性来自定义标记:

Position(必需)
地图上标记位置的 LatLng 值。这是 Marker 对象唯一的必需属性。
Anchor
图像上将置于标记的 LatLng 位置的点。该点默认为图像底部的中间位置。
Alpha
设置标记的不透明度。默认值为 1.0。
Title
当用户点按标记时显示在信息窗口内的字符串。
Snippet
显示在标题下方的附加文本。
Icon
取代默认标记图像而显示的位图。
Draggable
如果您想允许用户移动标记,请将其设置为 true。默认值为 false
Visible
设为 false 可使标记不可见。默认值为 true
Flat 或 Billboard 朝向
默认情况下,标记使用 Billboard 朝向,也就是说系统会根据设备屏幕朝向(而不是地图表面)绘制标记。旋转、倾斜或缩放地图均不会改变标记的朝向。您可以将标记的朝向设置为平贴地球表面。Flat 标记会随地图的旋转而旋转,并在地图倾斜时改变视角。与 Billboard 标记一样,Flat 标记将在地图缩放时保持大小不变。
Rotation
标记的朝向,以顺时针度数表示。当标记为 Flat 标记时,默认位置会发生变化。Flat 标记的默认位置指向正北。如果标记不是 Flat 标记,则默认位置为朝上,而且旋转时标记始终朝向镜头。

下面这段代码可创建一个使用默认图标的简单标记。

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation));

      

自定义标记的颜色

通过向 icon() 方法传递 BitmapDescriptor 对象,您可以自定义默认标记图像的颜色。您可以使用 BitmapDescriptorFactory 对象中的一组预定义颜色,或者通过 BitmapDescriptorFactory.defaultMarker(float hue) 方法设置自定义标记颜色。色调是一个介于 0 和 360 之间的值,表示色轮上的点。

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));

      

自定义标记的不透明度

您可以通过 MarkerOptions.alpha() 方法控制标记的不透明度。您应将 Alpha 指定为介于 0.0 和 1.0 之间的浮点值,其中 0 表示完全透明,而 1 则表示完全不透明。

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .alpha(0.7f)
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(new MarkerOptions()
    .position(melbourneLocation)
    .alpha(0.7f));

      

自定义标记图像

您可以将默认标记图像替换为自定义标记图像(通常称作图标)。自定义图标始终设置为 BitmapDescriptor,并且可通过 BitmapDescriptorFactory 类中的以下方法之一进行定义。

fromAsset(String assetName)
使用资源目录中的位图图像的名称创建自定义标记。
fromBitmap(Bitmap image)
使用位图图像创建自定义标记。
fromFile(String fileName)
使用位于内部存储中的位图图像文件的名称创建自定义图标。
fromPath(String absolutePath)
使用位图图像的绝对文件路径创建自定义标记。
fromResource(int resourceId)
使用位图图像的资源 ID 创建自定义标记。

下面这段代码可创建一个使用自定义图标的标记。

Kotlin



val melbourneLocation = LatLng(-37.813, 144.962)
val melbourne = map.addMarker(
    MarkerOptions()
        .position(melbourneLocation)
        .title("Melbourne")
        .snippet("Population: 4,137,400")
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow))
)

      

Java


final LatLng melbourneLocation = new LatLng(-37.813, 144.962);
Marker melbourne = map.addMarker(
    new MarkerOptions()
        .position(melbourneLocation)
        .title("Melbourne")
        .snippet("Population: 4,137,400")
        .icon(BitmapDescriptorFactory.fromResource(R.drawable.arrow)));

      

将标记平面化

标记图标通常以屏幕为参照物进行绘制;旋转、倾斜或缩放地图均不会改变标记的朝向。您可以将标记的朝向设置为平贴地球表面。采用这种朝向的标记将随地图的旋转而旋转,并在地图倾斜时改变视角。Flat 标记将在地图缩放时保持大小不变。

如需更改标记的朝向,请将标记的 flat 属性设置为 true

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .flat(true)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .flat(true));

      

旋转标记

您可以通过 Marker.setRotation() 方法让标记围绕其锚点旋转。旋转以与默认位置所呈顺时针角度来表示。当地图上的标记为 Flat 标记时,默认位置为指向北方。如果标记不是 Flat 标记,则默认位置为朝上,而且旋转时标记始终朝向镜头。

以下示例代码可将标记旋转 90°。将锚点设置为 0.5,0.5 可使标记围绕其中心而不是底部旋转。

Kotlin



val perthLocation = LatLng(-31.90, 115.86)
val perth = map.addMarker(
    MarkerOptions()
        .position(perthLocation)
        .anchor(0.5f, 0.5f)
        .rotation(90.0f)
)

      

Java


final LatLng perthLocation = new LatLng(-31.90, 115.86);
Marker perth = map.addMarker(
    new MarkerOptions()
        .position(perthLocation)
        .anchor(0.5f,0.5f)
        .rotation(90.0f));

      

标记 Z-index

Z-index 指定此标记相对于地图上其他标记的叠放顺序。Z-index 较高的标记绘制在 Z-index 较低的标记之上。默认 Z-index 值为 0

通过调用 MarkerOptions.zIndex() 在标记的选项对象上设置 Z-index,如以下代码段所示:

Kotlin



map.addMarker(
    MarkerOptions()
        .position(LatLng(10.0, 10.0))
        .title("Marker z1")
        .zIndex(1.0f)
)

      

Java


map.addMarker(new MarkerOptions()
    .position(new LatLng(10, 10))
    .title("Marker z1")
    .zIndex(1.0f));

      

您可以通过调用 Marker.getZIndex() 获取标记的 Z-index,并且可以通过调用 Marker.setZIndex() 对其进行更改。

标记始终在图块图层和其他非标记叠加层(地面叠加层、多段线、多边形和其他形状)之上绘制,而不考虑其他叠加层的 Z-index 值。事实上,与其他叠加层相比,可将标记视为位于单独的 Z-index 组中。

请参阅下文,了解 Z-index 对点击事件的影响

处理标记事件

您可以使用 Maps API 监听和响应标记事件。如需监听这些事件,您必须在标记所属的 GoogleMap 对象上设置相应的监听器。当地图上的某个标记发生事件时,系统将调用监听器的回调并传递相应 Marker 对象作为参数。如需将此 Marker 对象和您对 Marker 对象的引用进行比较,您必须使用 equals(),而非 ==

您可以监听以下事件:

标记点击事件

OnMarkerClickListener 可用于监听标记上的点击事件。如需在地图上设置此监听器,请调用 GoogleMap.setOnMarkerClickListener(OnMarkerClickListener)。当用户点击标记时,系统会调用 onMarkerClick(Marker),并以参数的形式传递标记。此方法会返回一个布尔值,指示您是否使用了该事件(即您想禁止默认行为)。如果它返回 false,则除了自定义行为外,还会发生默认行为。默认情况下,用户点击标记时,系统会显示相应的信息窗口(如果有),并移动镜头,使标记位于地图中心。

Z-index 对点击事件的影响:

  • 当用户点击标记的聚类时,将触发具有最高 Z-index 值的标记的点击事件。
  • 每个点击至多可触发一个事件。换句话说,点击不会传递到具有较低 Z-index 值的标记或其他叠加层。
  • 点击标记的聚类会导致后续点击在聚类中循环,从而依次选择每个标记。循环的顺序优先考虑 Z-index,然后才考虑点击点的距离。
  • 如果用户点击超出聚类的距离,则 API 将重新计算此聚类,并重置点击循环的状态,以便从头开始循环。
  • 点击事件依次作用于聚类中的每个标记,再作用于其他形状和叠加层,然后重新开始循环。
  • 事实上,与其他叠加层或形状(多段线、多边形、圆形和/或地面叠加层)相比,可将标记视为位于单独的 Z-index 组中,而不考虑其他叠加层的 Z-index 值。如果多个标记、叠加层或形状在彼此的顶部叠加,则点击事件首先在标记聚类中循环,然后根据其他可点击的叠加层或形状的 Z-index 值触发点击事件。

标记拖动事件

OnMarkerDragListener 可用于监听标记上的拖动事件。如需在地图上设置此监听器,请调用 GoogleMap.setOnMarkerDragListener。如需拖动标记,用户必须长按标记。用户的手指离开屏幕后,标记会留在手指离开屏幕前的位置。用户拖动标记时,系统会先调用 onMarkerDragStart(Marker)。如果用户正在拖动标记,则系统会不断调用 onMarkerDrag(Marker)。拖动结束时,系统会调用 onMarkerDragEnd(Marker)。您随时可以通过调用 Marker.getPosition() 获取标记的位置。