終於到了重頭戲,來替我們的專案建立 Google 地圖 !
今天實作的官方文件 :
新增地圖有以下幾個基本步驟 :
FragmentContainer
SupportMapFragment 物件新增至處理地圖的 Activity。OnMapReadyCallback 介面,並取得 GoogleMap 的實例。在開始之前,先來調整目前的畫面
main_activity.xml :
先將 RecyclerView 的程式碼註解,並加入 FragmentContainer :
<!--    <androidx.recyclerview.widget.RecyclerView-->
<!--        android:id="@+id/recycler_view"-->
<!--        android:layout_width="0dp"-->
<!--        android:layout_height="wrap_content"-->
<!--        app:layout_constraintBottom_toBottomOf="parent"-->
<!--        app:layout_constraintEnd_toEndOf="parent"-->
<!--        app:layout_constraintStart_toStartOf="parent"-->
<!--        app:layout_constraintTop_toTopOf="parent"-->
<!--        tools:listitem="@layout/item_cafe" />-->
<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" />
目前的 main_activity.xml :
<?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">
    <TextView
        android:id="@+id/tv_err"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:textSize="16sp"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="GET"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />
    <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.recyclerview.widget.RecyclerView-->
    <!--        android:id="@+id/recycler_view"-->
    <!--        android:layout_width="0dp"-->
    <!--        android:layout_height="wrap_content"-->
    <!--        app:layout_constraintBottom_toBottomOf="parent"-->
    <!--        app:layout_constraintEnd_toEndOf="parent"-->
    <!--        app:layout_constraintStart_toStartOf="parent"-->
    <!--        app:layout_constraintTop_toTopOf="parent"-->
    <!--        tools:listitem="@layout/item_cafe" />-->
    <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 修改 initView() 程式碼,把 RecyclerView 的初始化也註解 :
private fun initView() {
    adapter = MainAdapter(mutableListOf())
//        binding.recyclerView.apply {
//
//            layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
//            adapter = this@MainActivity.adapter
//        }
}
建立 Fragment 可以分為靜態和動態,這邊直接使用動態新增 :
在 MainActivity 內的 init() 內建立 SupportMapFragment:
private fun initView() {
    adapter = MainAdapter(mutableListOf())
    // TODO: MapFragment
    val mapFragment = SupportMapFragment.newInstance()
    supportFragmentManager
        .beginTransaction()
        .add(R.id.fragment_container, mapFragment)
        .commit()
}
這邊的 fragment_container 是剛剛在 main_activity.xml 加入的 fragment 容器 FragmentContainerView
class MainActivity : AppCompatActivity(), OnMapReadyCallback {
    // ...
}
覆寫 callback 的方法,以取得 GoogleMap 實例 :
override fun onMapReady(googleMap: GoogleMap) {
    googleMap.addMarker(
        MarkerOptions()
            .position(LatLng(0.0, 0.0))
            .title("Marker")
    )
}
輸入上面的經緯度會出現「空虛島」,超酷的 !
最後就是最重要的事情,我們需要和使用者取得權限,這邊新增 requestPermissions() :
private fun requestPermissions() {
    val REQUEST_EXTERNAL = 1;
    val PERMISSIONS_LIST = arrayOf(
        Manifest.permission.INTERNET,
        Manifest.permission.ACCESS_NETWORK_STATE,
        Manifest.permission.READ_PHONE_STATE,
        Manifest.permission.ACCESS_FINE_LOCATION,
        Manifest.permission.ACCESS_COARSE_LOCATION
    )
    var permission =
        ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    permission += ActivityCompat.checkSelfPermission(
        this,
        Manifest.permission.ACCESS_COARSE_LOCATION
    )
    if (permission != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, PERMISSIONS_LIST, REQUEST_EXTERNAL)
    }
}
在 onCreate() 初始化的時候,動態的和使用者取得專案需要的權限。
現在準備得差不多,來運行一下 !
