iT邦幫忙

2023 iThome 鐵人賽

DAY 12
0
Mobile Development

Google Maps SDK for Android 與 GIS App 開發筆記系列 第 12

Day 12: Google Maps SDK for Android –Marker 標記與互動事件

  • 分享至 

  • xImage
  •  

前言

在地圖上最常見的物件就是 Marker (官方翻譯為標記),在地圖上它代表的是一個點的位置,所以它所關聯的空間資訊就是經緯度。

話不多說,就讓我們進到實際製作的階段吧。

實作

還記得前面兩天的 TileOverlay 都是透過TileOverlayOptions 來設定,並透過 addTileOverlay() 來加入到 GoogleMap 上。

Marker 概念上也是如此。

  1. MarkerOptions:設定 Marker 的樣式。
  2. GoogleMap.addMarker() 用這個方法在地圖上建立 Marker
  3. Marker: 成功加入到地圖上後會取得的物件。

加入 Marker

private var googleMap: GoogleMap? = null


private var simpleMarker: Marker? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(binding.root)
    binding.mapView.onCreate(savedInstanceState)

    binding.mapView.getMapAsync {
        // 略...

        
        simpleMarker = addSimpleMarker(it)
    }
}

/**
 * 加入基本款的標記到地圖並取得 Marker 物件
 *
 * @param map
 * @return Marker
 */
private fun addSimpleMarker(map: GoogleMap): Marker? {
    val taichungOpera = LatLng(24.1627, 120.6403)
    return map.addMarker(
        MarkerOptions()
            .position(taichungOpera)
    )
}

將地圖上的 Marker 移除

TileOverlay 一樣,呼叫 Marker 中的 remove() 方法,即可將 Marker 從地圖上移除。

simpleMarker?.remove()

基本款樣式

Marker 的 Icon 除了預設的紅色外,還有其他顏色可以設定。

不過在那之前,要先知道,Marker 的 Icon 樣式是透過 MarkerOptions().icon() 來做設定。
icon() 所需要傳入的 BitmapDescriptor 參數,則可以透過 BitmapDescriptorFactory

像是以下的範例,會是在台中中央公園的點位上,加上一個藍色的 Marker

private fun addBlueMarkers(map: GoogleMap) {
    val centralPark = LatLng(24.1858, 120.6533)
    map.addMarker(MarkerOptions()
        .position(centralPark)
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
    )
}

https://ithelp.ithome.com.tw/upload/images/20230926/20160271x3zSjXefwc.png

除了 BitmapDescriptorFactory.HUE_BLUE (藍色) 外,還有其他種顏色可選。

https://ithelp.ithome.com.tw/upload/images/20230926/20160271LWjhPJMVhh.png

如果都沒有喜歡的,沒關係,明天的客製化 Marker 會聊到如何自定義。

InfoWindow 資訊視窗

除了調整 Marker 的圖示外,透過 MarkerOptions()title()snippet(),可以讓 Marker 在點擊時,在 Marker 上方出現一個小資訊視窗

private fun addMarkerWithInfo(map: GoogleMap) {
    val university = LatLng(24.1789, 120.6464)
    map.addMarker(MarkerOptions()
        .position(university)
        // 黑體標題
        .title("逢甲大學")
        // 灰體副標題
        .snippet("${university.latitude} , ${university.longitude}")
        .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
    )
}

InfoWindow 客製化

除了預設的 UI,也是可以透過 InfoWindowAdapter 自定如下方的 InfoWindow。

https://ithelp.ithome.com.tw/upload/images/20230926/201602719ncqvJR6YS.png
圖片來源:官方文件

但以我自己的經驗,實務上比較少使用這個 API,反而圖標上的資訊通常會搭配其他客製化 UI,如 BottomSheetDialog 來呈現。

有興趣的人可以參考官方文件的說明與範例,如果有遇到問題,也歡迎在下方留言區討論~

Marker 點擊事件

GoogleMap.OnMarkerClickListener

點擊事件指的是使用者點擊 Marker 所觸發的事件,實際的實作方式如下。

點擊事件的監聽是設定在 GoogleMap 之上,意味著所有的 Marker 的點擊事件都會透過這個 OnMarkerClickListener.onMarkerClick(marker): Boolean 傳出。

// 設定地圖的 Marker 點擊事件監聽
map.setOnMarkerClickListener { clickedMarker ->
    // 將被點擊的 Marker 的標題與經緯度取出並用 Toast 顯示
    Toast.makeText(
        this@MarkerActivity,
        "${clickedMarker.title} / ${clickedMarker.position.latitude} , ${clickedMarker.position.longitude}",
        Toast.LENGTH_LONG
    ).show()
    
    // 回傳 false 表示點擊事件會繼續傳遞,讓 SDK 執行預設的行為
    return@setOnMarkerClickListener false
}

https://ithelp.ithome.com.tw/upload/images/20230926/20160271QqZy97oiKU.png

這個點擊事件要特別注意的事情是,當 onMarkerClicked() 的回傳值設為

  • true: 代表點擊事件會完全由我們處理,預設的 Marker 點擊行為不會被觸發。
  • false: 反之,預設的 Marker 行為會按照預設的模式執行。

預設的點擊行為:地圖將 Marker 移至目前視窗的中心,如有 InfoWindow 則會顯示。

可拖曳的 Marker

到目前為止所介紹的 Marker 都是固定在特定點位,而可拖曳的 Marker 是可以讓使用者長按並移動它在地圖上的位置。

以下範例,我們建立了一個位在台中青海家樂福的綠色 Marker,並使用 draggable(true)Marker 可以被拖曳。

private fun addDraggableMarker(map: GoogleMap) {
    val carrefour = LatLng(24.1702, 120.6447)
    map.addMarker(
        MarkerOptions()
            .position(carrefour)
            .draggable(true)
            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN))
    )
}

這個拖曳功能比較常見的應用,就是讓使用者在圖面上標記經緯度。

Marker 拖曳事件

跟點擊事件一樣,拖曳事件的監聽一樣是設定在 GoogleMap 上,透過 setOnMarkerDragListener() 加入 OnMarkerDragListener 介面負責監聽。

map.setOnMarkerDragListener(object : OnMarkerDragListener{
    override fun onMarkerDrag(marker: Marker) {
        // Marker 移動中
        Log.d(TAG, "onMarkerDrag: 移動中")
    }
    override fun onMarkerDragEnd(marker: Marker) {
        // Marker 移動結束
        Toast.makeText(
            this@MarkerActivity,
            "Marker 移動結束",
            Toast.LENGTH_SHORT
        ).show()
    }
    override fun onMarkerDragStart(marker: Marker) {
        // Marker 開始移動
        Toast.makeText(
            this@MarkerActivity,
            "Marker 移動開始",
            Toast.LENGTH_SHORT
        ).show()
    }
})

小結

以上就是基本款的 Marker 設定與常見的互動事件,明天我們會接著看 Marker 的客製化。

那就一樣,明天見啦~/images/emoticon/emoticon08.gif


上一篇
Day 11: Google Maps SDK for Android–離線圖層套疊 MBTiles
下一篇
Day 13: Google Maps SDK for Android–自訂 Marker 外觀
系列文
Google Maps SDK for Android 與 GIS App 開發筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言