iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
Mobile Development

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

Day 13: Google Maps SDK for Android–自訂 Marker 外觀

  • 分享至 

  • xImage
  •  

前言

延續昨天聊到的 Marker,昨天對於外觀的設定只有提到顏色,今天會介紹更多外觀樣式上的調整。

實作

透明度調整 MarkerOptions.alpha()

Marker 可以設定透明度,範圍是 1.0 (不透明) 0.0f (完全透明)。

private fun addTransparentMarker(map: GoogleMap) {
    val taichungOpera = LatLng(24.1627, 120.6403)
    map.addMarker(
        MarkerOptions()
            .position(taichungOpera)
            .alpha(0.5f) // 設定透明度 50%
    )
}

https://ithelp.ithome.com.tw/upload/images/20230927/20160271Sqwl5FZGlU.png

將立體的標誌平貼於地圖 MarkerOptions().flat(true)

如果你有注意到,其實預設的 Marker 並非是平貼在地圖上,而是像只有尖端觸碰在地圖上。而且,當你旋轉地圖的時候,Marker 永遠都會朝上。

private fun addFlatMarker(map: GoogleMap) {
    val latLng = LatLng(24.1627, 120.641)
    map.addMarker(
        MarkerOptions()
            .position(latLng)
            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
            // 設定平貼
            .flat(true)
    )
}

https://ithelp.ithome.com.tw/upload/images/20230927/20160271fsAEBWuzin.png

旋轉 Marker

平貼在地圖上的 Marker,預設會是頭朝北擺放。如果不是平貼,則會永遠朝螢幕上方。

這個部份的效果,可以將前面兩個範例放在同一張地圖,並將地圖稍做旋轉應該就會發現差異。

那如果要設定平貼狀態的 Marker 朝向,可以使用 MarkerOptions().rotation() 方法。旋轉是以順時針方向旋轉。

private fun addRotationMarker(map: GoogleMap) {
    val latLng = LatLng(24.1627, 120.641)
    map.addMarker(
        MarkerOptions()
            .position(latLng)
            .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE))
            .flat(true)
            // 設定旋轉時的基準點
            .anchor(0.5f, 0.5f)
            // 順時針旋轉 90 度
            .rotation(90f)
    )
}

另外補充 anchor() 方法,常與 flat()rotation() 搭配使用。因為預設 rotation() 的旋轉是以 Marker 的底部為基準,如果要調整基準點,就需要使用這個方法。

https://ithelp.ithome.com.tw/upload/images/20230927/20160271MCnWTYkQgq.png

更換 Marker Icon

前面幾個調整雖然也有些變化,但是 Icon 都還是水滴形狀的預設 Marker。

如果要更換 Marker Icon,一樣是使用MarkerOptions().icon() 方法,並傳入 BitmapDescriptor

BitmapDescriptor 的建立一樣是使用 BitmapDescriptorFactory,有以下幾種方式:

  1. fromAsset(String assetName): 取用 asset 資料夾內的 PNG 圖片。
  2. fromBitmap(Bitmap image): 傳入 Bitmap
  3. fromFile(String fileName): 傳入 App 內部儲存空間的 PNG 圖片。
  4. fromPath(String absolutePath): 傳入PNG的絕對路徑。
  5. fromResource(int resourceId): 從 drawable 的 resource 中引入,檔案要是 PNG。(這個方式最簡單)

fromResource(int resourceId) 範例

我從 Icons8 網站下載了一個免費的 Android Icon,並把它放到 drawable 資料夾內,再使用 fromResource() 取用。

private fun addResourceIconMarker(map: GoogleMap) {
    val latLng = LatLng(24.1627, 120.645)
    map.addMarker(
        MarkerOptions()
            .position(latLng)
            .icon(BitmapDescriptorFactory.fromResource(R.drawable.icons8_android_48))
            .flat(true)
    )
}

https://ithelp.ithome.com.tw/upload/images/20230927/20160271qGo6DFZV6R.png

將自定的 View 轉 Bitmap 後當 Marker Icon

實務上有碰過一些需求,是 Marker 上的 Icon 必須動態顯示數值,這時候可以用 IconGenerator 來做到這件事情。

IconGenerator 是 Google Maps Utility 下的一個類別,所以要使用的話,需要另外加入 dependency

build.gradle (app)

// Utilities for Maps SDK for Android (requires Google Play Services)
implementation("com.google.maps.android:android-maps-utils:3.5.3")

// Optionally add the Kotlin Extensions (KTX) for full Kotlin language support
// See latest version at https://github.com/googlemaps/android-maps-ktx
implementation("com.google.maps.android:maps-utils-ktx:4.0.0")

建立 Bitmap

private fun createMarkerBitmap(context: Context, label: String): Bitmap {
    val inflater = LayoutInflater.from(context)
    val binding: MarkerWithTextBinding = MarkerWithTextBinding.inflate(inflater)
    val iconGenerator = IconGenerator(context)
    iconGenerator.setContentView(binding.root)
    iconGenerator.setBackground(ColorDrawable(Color.TRANSPARENT))
    binding.tvMarkerLabel.text = label
    return iconGenerator.makeIcon()
}

概念上很簡單,就是把設計好的 Marker view layout,使用 ViewBinding 將 View Inflate 出來。
再透過 IconGeneratorView 轉成 Bitmap

將 Marker Icon 改為做好的 Bitmap

private fun addMarkerWithText(map: GoogleMap) {
    val latLng = LatLng(24.1627, 120.665)
    val bitmap = createMarkerBitmap(this, "HelloWorld")
    map.addMarker(
        MarkerOptions()
            .position(latLng)
            .icon(BitmapDescriptorFactory.fromBitmap(bitmap))
            .flat(true)
    )
    
    bitmap.recycle()
}

https://ithelp.ithome.com.tw/upload/images/20230927/20160271EENToSHMZK.png

小結

今天介紹的 Marker 樣式調整都滿簡單的,我個人覺得最實用的是 View 轉 Bitmap 的 Marker。畢竟 UI 設計的需求千變萬化,傳統的圖示 UI 已無法滿足使用者的眼睛,這招熟悉的話,可以解決很多的設計需求~

以上就是我今天的分享,有任何問題歡迎留言討論。

明天見~/images/emoticon/emoticon07.gif


上一篇
Day 12: Google Maps SDK for Android –Marker 標記與互動事件
下一篇
Day 14: Google Maps SDK for Android–繪製線段 Polyline
系列文
Google Maps SDK for Android 與 GIS App 開發筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言