標記

選取平台: 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
  • 您操作的系統可能具備不重複的記錄 ID,而在該系統內,標記代表特定記錄。
  • 在決定標記的 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));

      

自訂標記

這部影片說明如何使用標記在地圖上顯示位置。

您可以為標記定義要顯示的自訂圖片,以取代預設圖示。 在定義圖示的過程中,您也需要設定一些屬性來調整標記的表現行為。

下列屬性可用來自訂標記:

位置 (必填)
地圖上標記位置的 LatLng 值。如為 Marker 物件,這便是唯一的必要屬性。
錨點
圖片上用於放置標記經緯度位置的點,預設在圖片的下方中央。
Alpha 值
可設定標記的不透明度。預設值為 1.0。
標題
使用者輕觸標記時,資訊視窗中顯示的字串。
文字片段
顯示在標題下的附加文字。
圖示
取代預設標記圖片顯示的點陣圖。
可拖曳
如果您想允許使用者移動標記,請設為 true。預設值為 false
可見
如要隱藏標記,請設為 false。預設值為 true
平放或直立方向
根據預設,標記是以直立方向呈現,也就是根據裝置螢幕方向繪製 (而非地圖表面)。旋轉、傾斜或縮放地圖不會改變標記的方向。您可以將標記的方向設定為平貼於地表。地圖旋轉時,平放標記會跟著旋轉;地圖傾斜時,標記也會改變角度。和直立標記一樣,縮放地圖時,平放標記的大小不會改變。
旋轉
標記的方向,以順時針角度表示。如果是平放標記,則預設方向會改變;平放標記的預設方向為朝北。如果不是平放標記,則預設方向為朝上,且旋轉時標記始終面對攝影機。

下方程式碼片段使用預設圖示建立一個簡易標記。

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));

      

自訂標記顏色

BitmapDescriptor 物件傳遞至 icon() 方法,即可自訂預設標記圖片的顏色。您可以在 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 屬性設為 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() 方法。旋轉是以預設方向依順時針角度測量。如果標記平放在地圖上,則預設方向為朝北。如果不是平放標記,則預設方向為朝上,且旋轉時標記始終面對攝影機。

以下範例會將標記旋轉 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 值為 0

如要設定標記選項物件的 Z-index,請呼叫 MarkerOptions.zIndex(),如以下程式碼片段所示:

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() 來取得標記的位置。