標記

標記是用來標出地圖上的某個位置,您可以變更標記的預設顏色或圖示圖片,自訂屬於自己的標記。歡迎利用資訊視窗進一步查看有關標記的更多內容。

程式碼範例

GitHub 上的 ApiDemos 存放區包含說明各種標記功能的範例:

簡介

標記可用來指示地圖上的位置。預設標記採用外觀和風格與 Google 地圖一致的標準圖示。您可以透過 API 變更圖示的顏色、圖片或錨點。標記是 Marker 類型的物件,可利用 GoogleMap.addMarker(markerOptions) 方法加入地圖中。

使用者可以與標記互動。根據預設,標記會接收 click 事件,而且系統通常會將標記與事件監聽器搭配使用,藉此顯示資訊視窗。將標記的 draggable 屬性設為 true 可讓使用者變更標記位置,長按則可啟動標記移動功能。

根據預設,使用者輕觸標記時,地圖工具列會顯示在地圖的右下角,方便使用者快速存取 Google 地圖行動應用程式。當然,您也可以選擇停用工具列,詳情請參閱控制項指南

開始使用標記

本集 Maps Live 教學課程介紹利用 Maps SDK for Android 在地圖上加入標記的基本概念。

加入標記

以下範例說明如何在地圖中加入標記。標記是在座標 10,10 建立,當使用者點擊標記,資訊視窗中就會顯示「Hello world」字串。

@Override
public void onMapReady(GoogleMap map) {
    map.addMarker(new MarkerOptions()
        .position(new LatLng(10, 10))
        .title("Hello world"));
}

顯示標記的其他相關資訊

其中一項常見的規定是,在使用者輕觸地圖上的標記時,顯示地點或位置相關資訊。請參閱資訊視窗指南。

為資料與標記建立關聯

您可以使用 Marker.setTag() 儲存具有標記的任意資料物件,並使用 Marker.getTag() 擷取資料物件,如以下程式碼範例所示:

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

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

    private Marker mPerth;
    private Marker mSydney;
    private Marker mBrisbane;

    private GoogleMap mMap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.marker_demo);

        SupportMapFragment mapFragment =
                (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    /** Called when the map is ready. */
    @Override
    public void onMapReady(GoogleMap map) {
        mMap = map;

        // Add some markers to the map, and add a data object to each marker.
        mPerth = mMap.addMarker(new MarkerOptions()
                .position(PERTH)
                .title("Perth"));
        mPerth.setTag(0);

        mSydney = mMap.addMarker(new MarkerOptions()
                .position(SYDNEY)
                .title("Sydney"));
        mSydney.setTag(0);

        mBrisbane = mMap.addMarker(new MarkerOptions()
                .position(BRISBANE)
                .title("Brisbane"));
        mBrisbane.setTag(0);

        // Set a listener for marker click.
        mMap.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)。 您可以監聽標記的拖曳事件,方法如標記拖曳事件一節中所述。

下方程式碼片段代表的是在澳洲伯斯新增了一個可拖曳標記。

static final LatLng PERTH = new LatLng(-31.90, 115.86);
Marker perth = mMap.addMarker(new MarkerOptions()
                          .position(PERTH)
                          .draggable(true));

自訂標記

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

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

標記透過下列屬性支援自訂功能:

位置 (必填)
地圖上標記位置的 LatLng 值。如為 Marker 物件,這便是唯一的必要屬性。
錨點
在放置於標記經緯度位置的圖片上的點;預設位於圖片的下方中央處。
Alpha 值
可設定標記的不透明度。預設值為 1.0。
標題
使用者輕觸標記時,資訊視窗中顯示的字串。
文字片段
顯示在標題下的附加文字。
圖示
取代預設標記圖片顯示的點陣圖。
可拖曳
如果您想允許使用者移動標記,請設為 true。預設值為 false
可見
如要隱藏標記,請設為 false。預設值為 true
固定或看板方向
根據預設,標記的顯示方向會依據螢幕而定,而不會隨著攝影機旋轉或傾斜;固定標記的顯示方向則是依據實際地表而定,且會隨著攝影機旋轉或傾斜。這兩種標記都不會因縮放而改變大小;如果您想要這樣的效果,請改用區域疊加層。
旋轉
標記的方向,以順時針角度指定。如果是固定標記,則預設方向會改變;固定標記的預設方向為朝北。如果不是固定標記,則預設方向為朝上,且旋轉時標記始終面對攝影機。

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

static final LatLng MELBOURNE = new LatLng(-37.813, 144.962);
Marker melbourne = mMap.addMarker(new MarkerOptions()
                          .position(MELBOURNE));

自訂標記顏色

BitmapDescriptor 物件傳遞至 icon() 方法,即可自訂預設標記圖片的顏色。您可以在 BitmapDescriptorFactory 物件中使用一組預先定義的顏色,也可以使用 BitmapDescriptorFactory.defaultMarker(float hue) 方法設定自訂標記顏色。色調為介於 0 和 360 之間的值,每個值代表色彩轉輪上的一個點。

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

自訂標記不透明度

您可以使用 MarkerOptions.alpha() 方法控制標記的不透明度。 Alpha 值應指定為介於 0.0 和 1.0 之間的浮動值,其中 0 表示完全透明,1 表示完全不透明。

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

自訂標記圖片

您可以使用自訂標記圖片 (通常稱為圖示) 取代預設的標記圖片。自訂圖示一律會設為 BitmapDescriptor,並使用 BitmapDescriptorFactory 類別中的其中一種方法定義。

fromAsset(String assetName)
可使用素材資源目錄中的點陣圖圖片名稱建立自訂標記。
fromBitmap(Bitmap image)
可使用點陣圖圖片建立自訂標記。
fromFile(String fileName)
可使用位於內部儲存空間的點陣圖圖片檔名稱建立自訂圖示。
fromPath(String absolutePath)
可使用點陣圖圖片的絕對檔案路徑建立自訂標記。
fromResource(int resourceId)
可使用點陣圖圖片的資源 ID 建立自訂標記。

下方程式碼片段代表的是使用自訂圖示建立了一個標記。

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

固定標記

標記圖示通常以相對於螢幕的方式繪製,因此旋轉、傾斜或縮放地圖不會改變標記的方向。您可以將標記的方向設定為固定於地表上方。這樣一來,地圖旋轉時,標記也會跟著旋轉;地圖傾斜時,標記也會改變角度。不過縮放地圖時,固定標記的大小並不會改變。

如要變更標記的方向,請將標記的 flat 屬性設為 true

static final LatLng PERTH = new LatLng(-31.90, 115.86);
Marker perth = mMap.addMarker(new MarkerOptions()
                          .position(PERTH)
                          .flat(true));

旋轉標記

如要讓標記圍繞著錨點旋轉,您可以使用 Marker.setRotation() 方法。旋轉是以預設方向依順時針角度測量。如果標記固定在地圖上,則預設方向為朝北。如果不是固定標記,則預設方向為朝上,且旋轉時標記始終面對攝影機。

以下範例會將標記旋轉 90°。將錨點設定為 0.5,0.5,標記將圍繞其中心旋轉,而非其基底。

static final LatLng PERTH = new LatLng(-31.90, 115.86);
Marker perth = mMap.addMarker(new MarkerOptions()
                          .position(PERTH)
                          .anchor(0.5,0.5)
                          .rotation(90.0));

標記 Z-index

Z-index 會指定這個標記相對於地圖上其他標記的堆疊順序。系統會將 Z-index 順序較高的標記繪製在順序較低的標記之上。預設的 Z-index 值為 0

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

@Override
public void onMapReady(GoogleMap map) {
    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() 來取得標記的位置。