iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0

在成功串接咖啡廳資料以及在 Android 專案內顯示 Google 地圖後,接著要來逐步實現我們找咖啡專案的需求 :

  • [ ] 點擊地圖標記顯示商家資訊
  • [ ] 顯示我的位置附近的商家資訊
  • [ ] 在地圖上顯示咖啡廳標記
  • [ ] 點擊地圖標記顯示咖啡廳資訊
  • [ ] 顯示我的位置附近的咖啡廳資訊
  • [ ] 加入篩選功能

上述的需求是有順序的,來依序實現吧~~~

今日實作課程 :

範例實作

以下範例建立了一個經緯度在雪梨的標記 :

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

接著要在澳洲建立多個標記,標記的 icon 可以用多種方式實作。筆者只會實作專案可能會用到部分,我們先打開 MainActivity

把地圖先宣告為全域變數 :

private lateinit var map: GoogleMap

建立標記的 map :

/** map to store place names and locations */
private val places = mapOf(
    "BRISBANE" to LatLng(-27.47093, 153.0235),
    "MELBOURNE" to LatLng(-37.81319, 144.96298),
    "DARWIN" to LatLng(-12.4634, 130.8456),
    "SYDNEY" to LatLng(-33.87365, 151.20689),
    "ADELAIDE" to LatLng(-34.92873, 138.59995),
    "PERTH" to LatLng(-31.952854, 115.857342),
    "ALICE_SPRINGS" to LatLng(-24.6980, 133.8807)
)

建立 PlaceDetails class,用來儲存標記資訊 :

/**
 * This stores the details of a place that used to draw a marker
 */
class PlaceDetails(
    val position: LatLng,
    val title: String = "Marker",
    val snippet: String? = null,
    val icon: BitmapDescriptor = BitmapDescriptorFactory.defaultMarker(),
    val infoWindowAnchorX: Float = 0.5F,
    val infoWindowAnchorY: Float = 0F,
    val draggable: Boolean = false,
    val zIndex: Float = 0F)

建立自定義方法 addMarkersToMap(),用來將標記加到剛剛宣告的 Map 內 :

/**
 * Show all the specified markers on the map
 */
private fun addMarkersToMap() {

    val placeDetailsMap = mutableMapOf(
        // Uses a coloured icon
        "BRISBANE" to MainActivity.PlaceDetails(
            position = places.getValue("BRISBANE"),
            title = "Brisbane",
            snippet = "Population: 2,074,200",
            icon = BitmapDescriptorFactory
                .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
        ),

        // Uses a custom icon with the info window popping out of the center of the icon.
        "SYDNEY" to MainActivity.PlaceDetails(
            position = places.getValue("SYDNEY"),
            title = "Sydney",
            snippet = "Population: 4,627,300",
            icon = BitmapDescriptorFactory.fromResource(R.drawable.arrow),
            infoWindowAnchorX = 0.5f,
            infoWindowAnchorY = 0.5f
        ),

        // Will create a draggable marker. Long press to drag.
        "MELBOURNE" to MainActivity.PlaceDetails(
            position = places.getValue("MELBOURNE"),
            title = "Melbourne",
            snippet = "Population: 4,137,400",
            draggable = true
        ),

        // Use a vector drawable resource as a marker icon.
        "ALICE_SPRINGS" to MainActivity.PlaceDetails(
            position = places.getValue("ALICE_SPRINGS"),
            title = "Alice Springs",
            icon = vectorToBitmap(
                R.drawable.ic_android, Color.parseColor("#A4C639")
            )
        ),

        // More markers for good measure
        "PERTH" to MainActivity.PlaceDetails(
            position = places.getValue("PERTH"),
            title = "Perth",
            snippet = "Population: 1,738,800"
        ),

        "ADELAIDE" to MainActivity.PlaceDetails(
            position = places.getValue("ADELAIDE"),
            title = "Adelaide",
            snippet = "Population: 1,213,000"
        )

    )

    // add 4 markers on top of each other in Darwin with varying z-indexes
    (0 until 4).map {
        placeDetailsMap.put(
            "DARWIN ${it + 1}", MainActivity.PlaceDetails(
                position = places.getValue("DARWIN"),
                title = "Darwin Marker ${it + 1}",
                snippet = "z-index initially ${it + 1}",
                zIndex = it.toFloat()
            )
        )
    }

    // place markers for each of the defined locations
    placeDetailsMap.keys.map {
        with(placeDetailsMap.getValue(it)) {
            map.addMarker(
                MarkerOptions()
                    .position(position)
                    .title(title)
                    .snippet(snippet)
                    .icon(icon)
                    .infoWindowAnchor(infoWindowAnchorX, infoWindowAnchorY)
                    .draggable(draggable)
                    .zIndex(zIndex))

        }
    }
}

這邊範例還有一個自定義方法 vectorToBitmap() ,是用來將 *Drawable*轉成 BitmapDescriptor,我們之後不一定會用到,大概會暫時用原先 Google 的標記樣式 :

/**
 * Demonstrates converting a [Drawable] to a [BitmapDescriptor],
 * for use as a marker icon.
 */
private fun vectorToBitmap(@DrawableRes id : Int, @ColorInt color : Int): BitmapDescriptor {
    val vectorDrawable: Drawable? = ResourcesCompat.getDrawable(resources, id, null)
    if (vectorDrawable == null) {
        Log.e(TAG, "Resource not found")
        return BitmapDescriptorFactory.defaultMarker()
    }
    val bitmap = Bitmap.createBitmap(vectorDrawable.intrinsicWidth,
        vectorDrawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    vectorDrawable.setBounds(0, 0, canvas.width, canvas.height)
    DrawableCompat.setTint(vectorDrawable, color)
    vectorDrawable.draw(canvas)
    return BitmapDescriptorFactory.fromBitmap(bitmap)
}

最後是 onMapRead() ,前幾天都在和他玩的~~

// Update the map configuration at runtime.
override fun onMapReady(googleMap: GoogleMap) {

    // return early if the map was not initialised properly
    map = googleMap ?: return

    // create bounds that encompass every location we reference
    val boundsBuilder = LatLngBounds.Builder()

    // include all places we have markers for on the map
    places.keys.map { place -> boundsBuilder.include(places.getValue(place)) }
    val bounds = boundsBuilder.build()

    // Set the map coordinates to Kyoto Japan.
    val kyoto = LatLng(35.00116, 135.7681)

    with(map) {

        // Set the map type
        mapType = com.google.android.gms.maps.GoogleMap.MAP_TYPE_NORMAL

        // Display traffic 、指南針、縮放按鈕
        isTrafficEnabled = true
        uiSettings.isCompassEnabled = true
        uiSettings.isZoomControlsEnabled = true

        // Override the default content description on the view, for accessibility mode.
        // Ideally this string would be localised.
        setContentDescription("Map with lots of markers.")

        moveCamera(com.google.android.gms.maps.CameraUpdateFactory.newLatLngBounds(bounds, 50))
    }

    // Add lots of markers to the googleMap.
    addMarkersToMap()
}

這邊我也學案例寫法用比較 Kotlin,現在筆者的 Kotlin 還是寫得和 Java 一樣,不優雅 :(
差不多了,來運行看看 !

阿! 筆者今天改用 Android 裝置,然後用 Vysor 顯示在螢幕上,比較方便操作和截圖~~~

  • 未點擊標記

    d22_1.png

  • 點擊標記會顯示出標記詳細資訊 (剛剛的自定義類別 PlaceDetails)

    d22_2.png

寫範例專案的開發人員還特地放 Android 圖標,太可愛了吧~~~

今天只有精力實作範例,一定是連假前症候群,雙十連假快樂壓各位!

今日推推

這首好像偏冷門,覺得不錯聽的耶
Yes


上一篇
Day21 串接 Google Maps API - 在 Android 專案內使用地圖
下一篇
Day23 在 Google 地圖上顯示全台咖啡廳資訊 - 2 向使用者取得位置權限
系列文
喝咖啡要30天?一起用 Kotlin 打造尋找好喝咖啡的 App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言