FindYourCoffee 專案的需求 :
今天要來在 Google 地圖上顯示咖啡廳標記,然後我們也需要做一些調整 :
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)
}
}
執行結果 :
在 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)
}
成功顯示台北咖啡廳資訊,但居然有其他縣市的資料混進來了 !? 驚
又減少一個專案需求~~~開心