iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Mobile Development

Android 口罩地圖入門實戰 30 天 (使用 Kotlin 程式語言)系列 第 28

Day 28:Google Map 顯示目前位置

本篇文章同步發表在 HKT 線上教室 部落格,線上影音教學課程已上架至 UdemyYoutube 頻道。另外,想追蹤更多相關技術資訊,歡迎到 臉書粉絲專頁 按讚追蹤喔~

程式碼範例

範例名稱:Google Map 顯示目前位置
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載

範例名稱:清除標記
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載

範例名稱:目前所在位置,使用預設藍色小點呈現
開發人員:HKT (侯光燦)
程式語言:Kotlin
開發環境:Android Studio 4.1.2 & Android 11 & Kotlin 1.4.30
授權範圍:使用時必須註明出處且不得為商業目的之使用
範例下載點:點我下載

在之前的介紹當中,我們陸陸續續學會「如何獲取位置權限」、「如何檢查GPS是否開啟」、「如何獲取目前所在位置經緯度」和「 Google Map 基本使用方式」,綜合以上幾個單元的學習,今天,我們已經可以輕鬆做出,在 Google Map 上標示並顯示目前裝置所在位置的 APP 應用程式。

在地圖上標示目前位置

將昨天介紹的範例,部分區域變數,拉出來變為全域變數

private var googleMap: GoogleMap? = null
private lateinit var mFusedLocationProviderClient: FusedLocationProviderClient

原本 getLocationPermission 寫在 onCreate ,我們將他搬到 onMapReady,代表等地圖準備好,我們再去檢查與獲取權限與位置邏輯。

override fun onMapReady(googleMap: GoogleMap) {
    this.googleMap = googleMap
    getLocationPermission()
}

在 onLocationResult 裡,將獲取到經緯度指定到 currentLocation,透過地圖的 addMarker 將所在位置標示出來,然後透過 moveCamera 將地圖畫面移動到此處。

val currentLocation =
    LatLng(
        locationResult.lastLocation.latitude,
        locationResult.lastLocation.longitude
    )
googleMap?.addMarker(
    MarkerOptions().position(currentLocation).title("現在位置")
)
googleMap?.moveCamera(
    CameraUpdateFactory.newLatLngZoom(
        currentLocation, 15f
    )
)

輸出結果

移除標記

假設裝置位置不斷在改變,但我們沒有把舊的標記清掉,就會有很多之前位置點的標記。所以我們需要加入清除上一次標記的邏輯。

private var mCurrLocationMarker: Marker? = null

...
...
...

//清除所有標記
//googleMap?.clear()

//清除上一次位置標記
mCurrLocationMarker?.remove()

//當下位置存到一個 Marker 變數中,好讓下一次可以清除
mCurrLocationMarker =googleMap?.addMarker(
    MarkerOptions().position(currentLocation).title("現在位置")
)

MarkerOptions

Markers (標記、圖釘),可以在地圖呈現一個指引圖案,吸引用戶看這裡。如圖所示:

其中 MarkerOptions 常用屬性,整理如下:

  • position:標記經緯度位置,需傳入 LatLng,此欄位必填。
  • title:標題的文字
  • snippet:片段資訊(有字數限制過程,過長會呈現...)
  • Icon :標記圖案

更多 Markers 設定可以參考官方文件: Markers

設定 Icon 圖片來源為向量圖

設定 Markers 的 Icon 圖片需為 bitmap,這裡 KT 提供一個將向量圖片轉為 bitmap 的小程式。並擴充 Int 功能,新增轉 dp 和 px 功能。

package com.thishkt.pharmacydemo.util

import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.Drawable
import android.util.Log
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory


object ImgUtil {
    fun getBitmapDescriptor(
        context: Context,
        id: Int,
        width: Int = 0,
        height: Int = 0
    ): BitmapDescriptor? {
        val vectorDrawable: Drawable? =
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
                context.getDrawable(id)
            } else {
                ContextCompat.getDrawable(context, id)
            }
        return if (vectorDrawable != null) {
            if (width == 0) vectorDrawable.intrinsicWidth
            if (height == 0) vectorDrawable.intrinsicHeight
            vectorDrawable.setBounds(0, 0, width, height)
            val bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            val canvas = Canvas(bm);
            vectorDrawable.draw(canvas);
            BitmapDescriptorFactory.fromBitmap(bm);
        } else {
            null
        }
    }

    val Int.dp: Int
        get() = (this / Resources.getSystem().displayMetrics.density).toInt()

    val Int.px: Int
        get() = (this * Resources.getSystem().displayMetrics.density).toInt()
}

向量圖片取自 Android Studio 內建的 mask 向量圖,ic_baseline_masks_24.xml

<vector android:height="24dp" android:tint="#FF5722"
    android:viewportHeight="24" android:viewportWidth="24"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="@android:color/white" android:pathData="M19.5,6c-1.31,0 -2.37,1.01 -2.48,2.3C15.14,7.8 14.18,6.5 12,6.5c-2.19,0 -3.14,1.3 -5.02,1.8C6.87,7.02 5.81,6 4.5,6C3.12,6 2,7.12 2,8.5V9c0,6 3.6,7.81 6.52,7.98C9.53,17.62 10.72,18 12,18s2.47,-0.38 3.48,-1.02C18.4,16.81 22,15 22,9V8.5C22,7.12 20.88,6 19.5,6zM3.5,9V8.5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3c0,1.28 0.38,2.47 1.01,3.48C4.99,14.27 3.5,12.65 3.5,9zM20.5,9c0,3.65 -1.49,5.27 -3.01,5.98c0.64,-1.01 1.01,-2.2 1.01,-3.48v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1V9zM10.69,10.48c-0.44,0.26 -0.96,0.56 -1.69,0.76V10.2c0.48,-0.17 0.84,-0.38 1.18,-0.58C10.72,9.3 11.23,9 12,9s1.27,0.3 1.8,0.62c0.34,0.2 0.71,0.42 1.2,0.59v1.04c-0.75,-0.21 -1.26,-0.51 -1.71,-0.78C12.83,10.2 12.49,10 12,10C11.51,10 11.16,10.2 10.69,10.48z"/>
</vector>

MarkerOptions 設定參數

googleMap?.addMarker(
    MarkerOptions()
        .position(currentLocation).title("現在位置")
        .snippet("這裡可以顯示相關資訊,太過長會被截掉").icon(
            getBitmapDescriptor(
                mContext,
                R.drawable.ic_baseline_masks_24,
                60.px,
                60.px
            )
        )
)

輸出結果

地圖開啟預設位置

在 onMapReady 加入移動鏡頭到預設座標位置,這樣開啟時預設就會先看到此位置。

//台北101
private val defaultLocation = LatLng(25.0338483, 121.5645283)
...
...
...
override fun onMapReady(googleMap: GoogleMap) {
      ...
      
        googleMap.moveCamera(
            CameraUpdateFactory.newLatLngZoom(
                defaultLocation, 6f
            )
        )
    }

預設開啟資訊視窗

Marker 有一個 showInfoWindow 方法,即可在不用點任何標記下,預設開啟此標記的資訊視窗。

currLocationMarker?.showInfoWindow()

目前所在位置,使用預設藍色小點呈現

googleMap?.isMyLocationEnabled = true

輸出結果

參考資料

HKT 線上教室
https://tw-hkt.blogspot.com/

Freepik
https://www.freepik.com/

Select Current Place and Show Details on a Map
https://developers.google.com/maps/documentation/android-sdk/current-place-tutorial

MapsActivityCurrentPlace.kt
https://github.com/googlemaps/android-samples/blob/bb1492036ad171443f549054c7e750dfe1a5cc64/tutorials/kotlin/CurrentPlaceDetailsOnMap/app/src/main/java/com/example/currentplacedetailsonmap/MapsActivityCurrentPlace.kt


那今天【iThome 鐵人賽】就介紹到這邊囉~

順帶一提,KT 線上教室,臉書粉絲團,會不定期發佈相關資訊,不想錯過最新資訊,不要忘記來按讚,追蹤喔!也歡迎大家將這篇文章分享給更多人喔。

我們明天再見囉!!!掰掰~


上一篇
Day 27:Google Map 範本學習(2)
下一篇
Day 29:Google Map 自訂資訊視窗
系列文
Android 口罩地圖入門實戰 30 天 (使用 Kotlin 程式語言)30

尚未有邦友留言

立即登入留言