iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0

FindYourCoffee 專案的需求 :

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

今天要來在 Google 地圖上顯示咖啡廳標記,然後我們也需要做一些調整 :

  1. 將預設標記調整至台北 : 目前的預設座標是範例專案給的資料 - 澳洲,我們將預設地點改在台北
  2. 在地圖上顯示台北的咖啡廳標記 : 將 API 撈到的台北咖啡廳設為標記,並顯示在地圖上

GOGO~~~

調整預設標記

調整 main_activity.xml,將不必要的 UI 拿掉 :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    tools:context=".MainActivity">

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minWidth="50dp"
        android:minHeight="50dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragment_container"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

接著打開 MainActivity.kt,調整初始化的方法 initView(),拿掉和 RecyclerView 相關的程式碼 :

private fun initView() {

        lifecycleScope.launch(Dispatchers.Main) {

            binding.progressbar.visibility = View.VISIBLE
            viewModel.loadCafes()
        }

        val mapFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

調整 onMapReady(),將預設地點改為台北 :

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

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

    // 取得位置權限
    requestLocationPermissions()

    with(map) {

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

        // UI 設定 : 交通 、指南針、縮放按鈕
        isTrafficEnabled = true
        uiSettings.isCompassEnabled = true
        uiSettings.isZoomControlsEnabled = true

        // 設置預設標記 - 台北
        val taipei = LatLng(25.0329694, 121.5654177) 
        moveCamera(com.google.android.gms.maps.CameraUpdateFactory.newLatLngZoom(taipei, 10f))
        addMarker(
            MarkerOptions().position(taipei).title("台北")
        )

        // 我的位置點擊
        setOnMyLocationButtonClickListener(this@MainActivity)
        setOnMyLocationClickListener(this@MainActivity)
    }
}

執行結果 :

d25_1.png

顯示台北咖啡廳標記

onCreate() 內,我們在取得咖啡廳資料的地方取出咖啡廳的經緯度和設定詳細資訊 :

// 取得咖啡廳資料
viewModel.coffeeShopsLiveData.observe(this) { cafes ->

    binding.progressbar.visibility = View.GONE

    cafes.forEach {
        // 取出咖啡廳的經緯度
        placesMap = mutableMapOf(
            it.id to LatLng(it.latitude.toDouble(), it.longitude.toDouble())
        )

        // 設定咖啡廳的詳細資訊
        placeDetailsMap[it.id] = MainActivity.PlaceDetails(
            position = LatLng(it.latitude.toDouble(), it.longitude.toDouble()),
            title = it.name,
            icon = BitmapDescriptorFactory
                .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
        )
    }

		// ...
}

並依照剛剛設定的詳細資訊,將標記加入至地圖 :

private fun addMarkersToMap() {

    // 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))
        }
    }
}
// 取得咖啡廳資料
viewModel.coffeeShopsLiveData.observe(this) { cafes ->

    binding.progressbar.visibility = View.GONE

    cafes.forEach {
        // 取出咖啡廳的經緯度
        placesMap = mutableMapOf(
            it.id to LatLng(it.latitude.toDouble(), it.longitude.toDouble())
        )

        // 設定咖啡廳的詳細資訊
        placeDetailsMap[it.id] = MainActivity.PlaceDetails(
            position = LatLng(it.latitude.toDouble(), it.longitude.toDouble()),
            title = it.name,
            icon = BitmapDescriptorFactory
                .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
        )
    }

    // 將標記加入至地圖
    addMarkersToMap()

    // ...
}

最後是移動地圖

// 計算縮放級別與中心位置,讓所有咖啡廳皆可見
val boundsBuilder = LatLngBounds.Builder()
placesMap.keys.map { place -> boundsBuilder.include(placesMap.getValue(place)) }
val bounds = boundsBuilder.build()

// 移動地圖
val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 100)
map.moveCamera(cameraUpdate)

observe() 完整版 :

// 取得咖啡廳資料
viewModel.coffeeShopsLiveData.observe(this) { cafes ->

    binding.progressbar.visibility = View.GONE

    cafes.forEach {
        // 將咖啡廳的經緯度加入至 Map
        placesMap = mutableMapOf(
            it.id to LatLng(it.latitude.toDouble(), it.longitude.toDouble())
        )

        // 設定咖啡廳的詳細資訊
        placeDetailsMap[it.id] = MainActivity.PlaceDetails(
            position = LatLng(it.latitude.toDouble(), it.longitude.toDouble()),
            title = it.name,
            icon = BitmapDescriptorFactory
                .defaultMarker(BitmapDescriptorFactory.HUE_AZURE)
        )
    }

    // 將標記加入至地圖
    addMarkersToMap()

    // 計算縮放級別與中心位置,讓所有咖啡廳皆可見
    val boundsBuilder = LatLngBounds.Builder()
    placesMap.keys.map { place -> boundsBuilder.include(placesMap.getValue(place)) }
    val bounds = boundsBuilder.build()

    // 移動地圖
    val cameraUpdate = CameraUpdateFactory.newLatLngBounds(bounds, 100)
    map.moveCamera(cameraUpdate)
}

執行結果

成功顯示台北咖啡廳資訊,但居然有其他縣市的資料混進來了 !? 驚

d25_2.png

又減少一個專案需求~~~開心

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

今日推推

又是冷門到極點的歌
Yes


上一篇
Day24 在 Google 地圖上顯示全台咖啡廳資訊 - 3 顯示我的位置
下一篇
Day26 在 Google 地圖上顯示全台咖啡廳資訊 - 5 顯示客製化標記資訊
系列文
喝咖啡要30天?一起用 Kotlin 打造尋找好喝咖啡的 App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言