1. ก่อนที่คุณจะเริ่มต้น
Codelab นี้จะสอนวิธีผสานรวม Maps SDK สําหรับ Android กับแอปของคุณ และใช้ฟีเจอร์หลักโดยการสร้างแอปที่แสดงแผนที่ของร้านจักรยานในซานฟรานซิสโก แคลิฟอร์เนีย สหรัฐอเมริกา
สิ่งที่ต้องมีก่อน
- ความรู้เบื้องต้นเกี่ยวกับการพัฒนา Kotlin และ Android
สิ่งที่คุณจะทํา
- เปิดใช้และใช้ Maps SDK สําหรับ Android เพื่อเพิ่ม Google Maps ลงในแอป Android
- เพิ่ม ปรับแต่ง และจัดกลุ่มเครื่องหมาย
- วาดเส้นและรูปหลายเหลี่ยมบนแผนที่
- ควบคุมมุมมองของกล้อง
สิ่งที่ต้องมี
- Maps SDK สําหรับ Android
- บัญชี Google ที่เปิดใช้การเรียกเก็บเงิน
- Android Studio 2020.3.1 ขึ้นไป
- บริการ Google Play ที่ติดตั้งใน Android Studio
- อุปกรณ์ Android หรือโปรแกรมจําลอง Android ที่ใช้แพลตฟอร์ม Google APIs ที่ใช้ Android 4.2.2 ขึ้นไป (ดูขั้นตอนการติดตั้งเรียกใช้แอปใน Android จําลอง)
2. ตั้งค่า
สําหรับขั้นตอนการเปิดใช้ต่อไปนี้ คุณต้องเปิดใช้ Maps SDK สําหรับ Android
ตั้งค่า Google Maps Platform
หากยังไม่มีบัญชี Google Cloud Platform และโปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน โปรดดูคู่มือการเริ่มต้นใช้งาน Google Maps Platform เพื่อสร้างบัญชีสําหรับการเรียกเก็บเงินและโปรเจ็กต์
- ใน Cloud Console ให้คลิกเมนูแบบเลื่อนลงของโปรเจ็กต์ แล้วเลือกโปรเจ็กต์ที่ต้องการใช้สําหรับ Codelab นี้
- เปิดใช้ Google Maps Platform API และ SDK ที่จําเป็นสําหรับ Codelab นี้ใน Google Cloud Marketplace โดยทําตามขั้นตอนในวิดีโอนี้หรือเอกสารนี้
- สร้างคีย์ API ในหน้าข้อมูลเข้าสู่ระบบของ Cloud Console คุณสามารถทําตามขั้นตอนในวิดีโอนี้หรือเอกสารนี้ คําขอทั้งหมดสําหรับ Google Maps Platform ต้องใช้คีย์ API
3. การเริ่มใช้งานอย่างง่าย
โค้ดเริ่มต้นเพื่อช่วยให้คุณเริ่มต้นทําสิ่งต่อไปนี้ได้พร้อมด้วย Codelab เพื่อช่วยให้คุณเริ่มต้นใช้งานได้เร็วที่สุด คุณยินดีข้ามไปที่โซลูชันนี้ แต่ถ้าต้องการทําตามขั้นตอนทั้งหมดในการสร้างด้วยตนเอง ให้อ่านต่อไป
- โคลนที่เก็บหากคุณติดตั้ง
git
git clone https://github.com/googlecodelabs/maps-platform-101-android.git
หรือจะคลิกปุ่มต่อไปนี้เพื่อดาวน์โหลดซอร์สโค้ดก็ได้
- เมื่อได้รับรหัสแล้ว ให้เปิดโปรเจ็กต์ที่พบในไดเรกทอรี
starter
ใน Android Studio
4. เพิ่ม Google Maps
ในส่วนนี้ คุณจะต้องเพิ่ม Google Maps เพื่อให้โหลดเมื่อคุณเปิดแอป
เพิ่มคีย์ API
คุณต้องระบุคีย์ API ที่คุณสร้างในขั้นตอนก่อนหน้าให้กับแอปเพื่อให้ Maps SDK สําหรับ Android เชื่อมโยงคีย์กับแอปได้
- หากต้องการดําเนินการนี้ ให้เปิดไฟล์ชื่อ
local.properties
ในไดเรกทอรีรากของโปรเจ็กต์ (ระดับเดียวกับgradle.properties
และsettings.gradle
) - ในไฟล์ดังกล่าว ให้กําหนดคีย์ใหม่
GOOGLE_MAPS_API_KEY
โดยมีค่าเป็นคีย์ API ที่คุณสร้าง
local.properties
GOOGLE_MAPS_API_KEY=YOUR_KEY_HERE
โปรดทราบว่า local.properties
จะแสดงอยู่ในไฟล์ .gitignore
ในที่เก็บ Git เนื่องจากคีย์ API ของคุณถือเป็นข้อมูลที่ละเอียดอ่อนและไม่ควรเช็คอินการควบคุมแหล่งที่มาหากเป็นไปได้
- จากนั้น หากต้องการแสดง API เพื่อให้ใช้ทั่วทั้งแอป ให้ใส่ปลั๊กอิน Secrets Gradle Plugin for Android ในไฟล์
build.gradle
ของแอปที่อยู่ในไดเรกทอรีapp/
และเพิ่มบรรทัดต่อไปนี้ภายในบล็อกplugins
build.gradle ระดับแอป
plugins {
// ...
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin'
}
นอกจากนี้ คุณจะต้องแก้ไขไฟล์ build.gradle
ระดับโปรเจ็กต์ให้รวม pathpath ต่อไปนี้
build.gradle ระดับโปรเจ็กต์
buildscript {
dependencies {
// ...
classpath "com.google.android.libraries.mapsplatform.secrets-gradle-plugin:secrets-gradle-plugin:1.3.0"
}
}
ปลั๊กอินนี้จะทําให้คีย์ที่กําหนดไว้ภายในไฟล์ local.properties
ใช้เป็นตัวแปรบิลด์ในไฟล์ Manifest ของ Android และเป็นตัวแปรในคลาส BuildConfig
ที่ Gradle สร้างขึ้นในเวลาบิลด์ การใช้ปลั๊กอินนี้จะนําโค้ด Boilerplate ที่ต้องใช้ในการอ่านพร็อพเพอร์ตี้ออกจาก local.properties
เพื่อให้เข้าถึงได้ทั่วทั้งแอป
เพิ่มทรัพยากร Dependency ของ Google Maps
- ตอนนี้คุณสามารถเข้าถึงคีย์ API ภายในแอปได้แล้ว ขั้นตอนถัดไปคือเพิ่มทรัพยากร Dependency ของ Maps SDK สําหรับ Android ลงในไฟล์
build.gradle
ของแอป
ในโปรเจ็กต์เริ่มต้นที่มาพร้อมกับ Codelab นี้ เราได้เพิ่มทรัพยากร Dependency นี้ไว้แล้ว
build.gradle
dependencies {
// Dependency to include Maps SDK for Android
implementation 'com.google.android.gms:play-services-maps:17.0.0'
}
- ต่อไปให้เพิ่มแท็ก
meta-data
ใหม่ในAndroidManifest.xml
เพื่อส่งผ่านคีย์ API ที่สร้างไว้ในขั้นตอนก่อนหน้า ในการดําเนินการนี้ ให้เปิดไฟล์นี้ใน Android Studio แล้วเพิ่มแท็กmeta-data
ต่อไปนี้ภายในออบเจ็กต์application
ในไฟล์AndroidManifest.xml
ซึ่งจะอยู่ในapp/src/main
AndroidManifest.xml
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${GOOGLE_MAPS_API_KEY}" />
- ต่อไป สร้างไฟล์เลย์เอาต์ใหม่ชื่อ
activity_main.xml
ในไดเรกทอรีapp/src/main/res/layout/
แล้วกําหนดสิ่งต่อไปนี้
activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<fragment
class="com.google.android.gms.maps.SupportMapFragment"
android:id="@+id/map_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
เลย์เอาต์นี้มี FrameLayout
รายการที่มี SupportMapFragment
อยู่เพียงรายการเดียว ส่วนย่อยนี้มีออบเจ็กต์ GoogleMaps
ที่สําคัญซึ่งคุณใช้ในขั้นตอนต่อๆ ไป
- สุดท้าย ให้อัปเดตคลาส
MainActivity
ในapp/src/main/java/com/google/codelabs/buildyourfirstmap
โดยการเพิ่มโค้ดต่อไปนี้เพื่อลบล้างเมธอดonCreate
เพื่อให้คุณตั้งค่าเนื้อหาด้วยเลย์เอาต์ใหม่ที่คุณเพิ่งสร้างได้
กิจกรรมหลัก
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
- ทีนี้ดําเนินการต่อและเรียกใช้แอป คุณจะเห็นการโหลดแผนที่บนหน้าจอของอุปกรณ์
5. การจัดรูปแบบแผนที่ในระบบคลาวด์ (ไม่บังคับ)
คุณสามารถปรับแต่งรูปแบบแผนที่โดยใช้การจัดรูปแบบแผนที่ในระบบคลาวด์
สร้างรหัสแผนที่
หากคุณยังไม่ได้สร้างรหัสแผนที่ที่มีรูปแบบแผนที่เชื่อมโยงอยู่ โปรดดูคู่มือรหัสแผนที่เพื่อทําตามขั้นตอนต่อไปนี้
- สร้างรหัสแผนที่
- เชื่อมโยงรหัสแผนที่กับรูปแบบแผนที่
การเพิ่มรหัสแผนที่ลงในแอป
หากต้องการใช้รหัสแผนที่ที่คุณสร้างขึ้น ให้แก้ไขไฟล์ activity_main.xml
และส่งรหัสแผนที่ในแอตทริบิวต์ map:mapId
ของ SupportMapFragment
activity_main.xml
<fragment xmlns:map="http://schemas.android.com/apk/res-auto"
class="com.google.android.gms.maps.SupportMapFragment"
<!-- ... -->
map:mapId="YOUR_MAP_ID" />
เมื่อเสร็จแล้ว ให้เรียกใช้แอปเพื่อดูแผนที่ในรูปแบบที่คุณเลือก
6. เพิ่มเครื่องหมาย
ในงานนี้ คุณต้องเพิ่มเครื่องหมายบนแผนที่ที่แสดงถึงจุดสนใจที่คุณต้องการไฮไลต์บนแผนที่ ก่อนอื่น ให้เรียกรายการสถานที่ที่คุณระบุไว้ในโปรเจ็กต์เริ่มต้น แล้วเพิ่มสถานที่เหล่านั้นลงในแผนที่ ในตัวอย่างนี้ รายการเหล่านี้คือร้านจักรยาน
รับการอ้างอิงไปยัง GoogleMaps
ก่อนอื่น คุณต้องได้รับการอ้างอิงไปยังออบเจ็กต์ GoogleMap
เพื่อให้คุณใช้วิธีการของออบเจ็กต์นั้นได้ โดยเพิ่มโค้ดต่อไปนี้ในเมธอด MainActivity.onCreate()
ทันทีหลังจากเรียกไปที่ setContentView()
MainActivity.onCreate()
val mapFragment = supportFragmentManager.findFragmentById(
R.id.map_fragment
) as? SupportMapFragment
mapFragment?.getMapAsync { googleMap ->
addMarkers(googleMap)
}
การติดตั้งใช้งานจะค้นหา SupportMapFragment
ที่คุณเพิ่มในขั้นตอนก่อนหน้าก่อนโดยใช้เมธอด findFragmentById()
ในออบเจ็กต์ SupportFragmentManager
เมื่อได้รับข้อมูลอ้างอิงแล้ว ระบบจะเรียกใช้ getMapAsync()
ก่อนโดยผ่านแลมบ์ดา แลมบ์ดานี้คือตําแหน่งที่ส่งผ่านวัตถุ GoogleMap
ภายใน Labda นี้ ระบบจะเรียกใช้เมธอด addMarkers()
ซึ่งกําหนดไว้ในไม่ช้า
คลาสที่ให้ไว้: PlacesReader
ในโปรเจ็กต์เริ่มต้น ระบบส่งชั้นเรียน PlacesReader
ให้คุณแล้ว ชั้นเรียนนี้อ่านรายชื่อสถานที่ 49 แห่งที่จัดเก็บไว้ในไฟล์ JSON ชื่อ places.json
และแสดงผลสถานที่เหล่านี้เป็น List<Place>
สถานที่ดังกล่าวจะเป็นตัวแทนของร้านจักรยานรอบๆ ซานฟรานซิสโก แคลิฟอร์เนีย สหรัฐอเมริกา
หากมีข้อสงสัยเกี่ยวกับการใช้งานชั้นเรียนนี้ คุณจะเข้าถึงชั้นเรียนนี้ได้ใน GitHub หรือเปิดชั้นเรียน PlacesReader
ใน Android Studio
ผู้อ่านสถานที่
package com.google.codelabs.buildyourfirstmap.place
import android.content.Context
import com.google.codelabs.buildyourfirstmap.R
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import java.io.InputStream
import java.io.InputStreamReader
/**
* Reads a list of place JSON objects from the file places.json
*/
class PlacesReader(private val context: Context) {
// GSON object responsible for converting from JSON to a Place object
private val gson = Gson()
// InputStream representing places.json
private val inputStream: InputStream
get() = context.resources.openRawResource(R.raw.places)
/**
* Reads the list of place JSON objects in the file places.json
* and returns a list of Place objects
*/
fun read(): List<Place> {
val itemType = object : TypeToken<List<PlaceResponse>>() {}.type
val reader = InputStreamReader(inputStream)
return gson.fromJson<List<PlaceResponse>>(reader, itemType).map {
it.toPlace()
}
}
โหลดสถานที่
หากต้องการโหลดรายการร้านจักรยาน ให้เพิ่มพร็อพเพอร์ตี้ใน MainActivity
ที่ชื่อ places
และกําหนดดังนี้
MainActivity.places
private val places: List<Place> by lazy {
PlacesReader(this).read()
}
โค้ดนี้จะเรียกใช้เมธอด read()
ใน PlacesReader
ซึ่งแสดงผล List<Place>
Place
มีพร็อพเพอร์ตี้ชื่อ name
ชื่อสถานที่ และ latLng
ซึ่งเป็นพิกัดของสถานที่
สถานที่
data class Place(
val name: String,
val latLng: LatLng,
val address: LatLng,
val rating: Float
)
เพิ่มเครื่องหมายลงในแผนที่
เมื่อรายการสถานที่โหลดเข้าสู่ความทรงจําแล้ว ขั้นตอนต่อไปคือการแสดงสถานที่เหล่านี้ในแผนที่
- สร้างเมธอดใน
MainActivity
ที่ชื่อว่าaddMarkers()
แล้วกําหนดวิธีต่อไปนี้
MainActivity.addMarkers()
/**
* Adds marker representations of the places list on the provided GoogleMap object
*/
private fun addMarkers(googleMap: GoogleMap) {
places.forEach { place ->
val marker = googleMap.addMarker(
MarkerOptions()
.title(place.name)
.position(place.latLng)
)
}
}
วิธีนี้ทําซ้ําผ่านรายการ places
ตามด้วยการเรียกใช้เมธอด addMarker()
ในออบเจ็กต์ GoogleMap
ที่ระบุ ตัวทําเครื่องหมายนี้สร้างขึ้นจากการสร้างออบเจ็กต์ MarkerOptions
ซึ่งให้คุณปรับแต่งตัวทําเครื่องหมายเองได้ ในกรณีนี้ ให้ระบุตําแหน่งและตําแหน่งของเครื่องหมาย รวมทั้งชื่อร้านจักรยานและพิกัดตามลําดับ
- ไปที่แอปแล้วเดินไปที่ซานฟรานซิสโก เพื่อดูเครื่องหมายที่เพิ่งเพิ่มไป
7. ปรับแต่งเครื่องหมาย
มีตัวเลือกการปรับแต่งมากมายสําหรับเครื่องหมายที่คุณเพิ่งเพิ่มเพื่อช่วยให้โดดเด่นและแสดงข้อมูลที่เป็นประโยชน์แก่ผู้ใช้ ในงานนี้ คุณจะได้สํารวจเครื่องมือบางอย่างด้วยการปรับแต่งรูปภาพของเครื่องหมายแต่ละรายการ รวมถึงหน้าต่างข้อมูลที่แสดงเมื่อแตะเครื่องหมาย
การเพิ่มหน้าต่างข้อมูล
โดยค่าเริ่มต้น หน้าต่างข้อมูลเมื่อคุณแตะเครื่องหมายจะแสดงชื่อและตัวอย่างข้อมูล (หากตั้งค่าไว้) คุณปรับแต่งเพื่อให้แสดงข้อมูลเพิ่มเติมได้ เช่น ที่อยู่และคะแนนของสถานที่
สร้างmark_info_contents.xml
ขั้นแรก ให้สร้างไฟล์เลย์เอาต์ใหม่ที่ชื่อ marker_info_contents.xml
- วิธีการคือ คลิกขวาที่โฟลเดอร์
app/src/main/res/layout
ในมุมมองโปรเจ็กต์ใน Android Studio แล้วเลือก New > Layout Resource File
- ในกล่องโต้ตอบ ให้พิมพ์
marker_info_contents
ในช่องชื่อไฟล์ และLinearLayout
ในช่องRoot element
จากนั้นคลิกตกลง
หลังจากขยายไฟล์เลย์เอาต์นี้ ระบบก็จะแสดงเนื้อหานี้ในรูปแบบตัวแทนเนื้อหาภายในหน้าต่างข้อมูล
- คัดลอกเนื้อหาในข้อมูลโค้ดต่อไปนี้ ซึ่งจะเพิ่ม
TextViews
3 รายการภายในกลุ่มมุมมองLinearLayout
แนวตั้ง และเขียนทับโค้ดเริ่มต้นในไฟล์
Mark_info_contents.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="8dp">
<TextView
android:id="@+id/text_view_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold"
tools:text="Title"/>
<TextView
android:id="@+id/text_view_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="16sp"
tools:text="123 Main Street"/>
<TextView
android:id="@+id/text_view_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/black"
android:textSize="16sp"
tools:text="Rating: 3"/>
</LinearLayout>
สร้างการติดตั้งใช้งาน InfoWindowAdapter
หลังจากสร้างไฟล์เลย์เอาต์สําหรับหน้าต่างข้อมูลที่กําหนดเองแล้ว ขั้นตอนถัดไปคือการใช้อินเทอร์เฟซ GoogleMaps.InfoWindowAdapter อินเทอร์เฟซนี้มี 2 วิธี ได้แก่ getInfoWindow()
และ getInfoContents()
ทั้ง 2 วิธีนี้ส่งคืนออบเจ็กต์ View
ที่ไม่บังคับ ซึ่งมีนโยบายเก่าใช้ปรับแต่งหน้าต่างเอง ขณะที่ตัวเลือกหลังคือการปรับแต่งเนื้อหา ในกรณีของคุณ ให้ใช้ทั้ง 2 อย่างและปรับแต่งการคืนสินค้าของ getInfoContents()
ขณะแสดงผลเป็น Null ใน getInfoWindow()
ซึ่งระบุว่าควรใช้หน้าต่างเริ่มต้น
- สร้างไฟล์ Kotlin ใหม่ชื่อ
MarkerInfoWindowAdapter
ในแพ็กเกจเดียวกับMainActivity
โดยคลิกขวาที่โฟลเดอร์app/src/main/java/com/google/codelabs/buildyourfirstmap
ในมุมมองโปรเจ็กต์ใน Android Studio จากนั้นเลือก New > Kotlin File/Class
- ในกล่องโต้ตอบ ให้พิมพ์
MarkerInfoWindowAdapter
และไฮไลต์ไฟล์ไว้
- เมื่อสร้างไฟล์แล้ว ให้คัดลอกเนื้อหาในข้อมูลโค้ดต่อไปนี้ลงในไฟล์ใหม่
MarkerInfoWindowAdapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.TextView
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.Marker
import com.google.codelabs.buildyourfirstmap.place.Place
class MarkerInfoWindowAdapter(
private val context: Context
) : GoogleMap.InfoWindowAdapter {
override fun getInfoContents(marker: Marker?): View? {
// 1. Get tag
val place = marker?.tag as? Place ?: return null
// 2. Inflate view and set title, address, and rating
val view = LayoutInflater.from(context).inflate(
R.layout.marker_info_contents, null
)
view.findViewById<TextView>(
R.id.text_view_title
).text = place.name
view.findViewById<TextView>(
R.id.text_view_address
).text = place.address
view.findViewById<TextView>(
R.id.text_view_rating
).text = "Rating: %.2f".format(place.rating)
return view
}
override fun getInfoWindow(marker: Marker?): View? {
// Return null to indicate that the
// default window (white bubble) should be used
return null
}
}
ในเนื้อหาของเมธอด getInfoContents()
ระบบจะสังเกตเครื่องหมายที่ระบุในเมธอดเป็นประเภท Place
และหากแคสต์ไม่ได้ ระบบจะแสดงผลค่า Null (หากยังไม่ได้ตั้งค่าพร็อพเพอร์ตี้แท็กใน Marker
แต่คุณจะทําในขั้นตอนถัดไป)
ถัดไป เลย์เอาต์ marker_info_contents.xml
จะมีค่าสูงเกินจริงตามการตั้งค่าข้อความที่มี TextViews
เป็นแท็ก Place
อัปเดตกิจกรรมหลัก
หากต้องการเลื่อนคอมโพเนนต์ทั้งหมดที่สร้างไว้ออกไป คุณจะต้องเพิ่มบรรทัด 2 บรรทัดใน MainActivity
ชั้นเรียน
ขั้นแรก หากต้องการส่งผ่าน InfoWindowAdapter
ที่กําหนดเองซึ่งเป็น MarkerInfoWindowAdapter
ในการเรียกเมธอด getMapAsync
ให้เรียกใช้เมธอด setInfoWindowAdapter()
ในออบเจ็กต์ GoogleMap
และสร้างอินสแตนซ์ใหม่ของ MarkerInfoWindowAdapter
- โดยเพิ่มโค้ดต่อไปนี้หลังจากเรียกเมธอด
addMarkers()
ในgetMapAsync()
แลมบ์ดา
MainActivity.onCreate()
// Set custom info window adapter
googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))
และสุดท้าย คุณจะต้องตั้งค่าสถานที่แต่ละแห่งเป็นพร็อพเพอร์ตี้ของแท็กสําหรับเครื่องหมายทุกตัวที่เพิ่มลงในแผนที่
- โดยแก้ไขการเรียกใช้
places.forEach{}
ในฟังก์ชันaddMarkers()
ด้วยสิ่งต่อไปนี้
MainActivity.addMarkers()
places.forEach { place ->
val marker = googleMap.addMarker(
MarkerOptions()
.title(place.name)
.position(place.latLng)
.icon(bicycleIcon)
)
// Set place as the tag on the marker object so it can be referenced within
// MarkerInfoWindowAdapter
marker.tag = place
}
เพิ่มรูปภาพตัวทําเครื่องหมายที่กําหนดเอง
การปรับแต่งภาพเครื่องหมายเป็นหนึ่งในวิธีสนุกๆ ในการสื่อสารประเภทตําแหน่งที่เครื่องหมายบนแผนที่ของคุณ ในขั้นตอนนี้ คุณจะแสดงจักรยานแทนเครื่องหมายสีแดงเริ่มต้นเพื่อแสดงร้านค้าแต่ละแห่งบนแผนที่ โปรเจ็กต์เริ่มต้นมีไอคอนจักรยาน ic_directions_bike_black_24dp.xml
ใน app/src/res/drawable
ที่คุณใช้
ตั้งค่าบิตแมปที่กําหนดเองบนเครื่องหมาย
คุณสามารถใช้ไอคอนจักรยานที่วาดได้ขณะขับขี่ได้ ขั้นตอนถัดไปคือตั้งค่าไอคอนที่วาดได้ให้เป็นเครื่องหมายแต่ละรายการ' บนแผนที่ MarkerOptions
มีเมธอด icon
ซึ่งใช้ใน BitmapDescriptor
ที่คุณใช้เพื่อให้บรรลุวัตถุประสงค์นี้
ก่อนอื่น คุณจะต้องแปลงเวกเตอร์ที่วาดได้ที่คุณเพิ่งเพิ่มลงใน BitmapDescriptor
ไฟล์ชื่อ BitMapHelper
ที่รวมอยู่ในโปรเจ็กต์เริ่มต้นมีฟังก์ชันผู้ช่วยที่เรียกว่า vectorToBitmap()
ซึ่งจะทําหน้าที่ดังกล่าว
BitmapHelper
package com.google.codelabs.buildyourfirstmap
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.util.Log
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.DrawableCompat
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.BitmapDescriptorFactory
object BitmapHelper {
/**
* Demonstrates converting a [Drawable] to a [BitmapDescriptor],
* for use as a marker icon. Taken from ApiDemos on GitHub:
* https://github.com/googlemaps/android-samples/blob/main/ApiDemos/kotlin/app/src/main/java/com/example/kotlindemos/MarkerDemoActivity.kt
*/
fun vectorToBitmap(
context: Context,
@DrawableRes id: Int,
@ColorInt color: Int
): BitmapDescriptor {
val vectorDrawable = ResourcesCompat.getDrawable(context.resources, id, null)
if (vectorDrawable == null) {
Log.e("BitmapHelper", "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)
}
}
วิธีนี้ใช้ Context
, รหัสทรัพยากรที่วาดได้ และจํานวนเต็มสี รวมถึงสร้างการนําเสนอ BitmapDescriptor
ของวิธีดังกล่าว
ใช้วิธีการผู้ช่วยในการประกาศพร็อพเพอร์ตี้ใหม่ชื่อ bicycleIcon
และให้คําจํากัดความต่อไปนี้ MainActivity.bicycleIcon
private val bicycleIcon: BitmapDescriptor by lazy {
val color = ContextCompat.getColor(this, R.color.colorPrimary)
BitmapHelper.vectorToBitmap(this, R.drawable.ic_directions_bike_black_24dp, color)
}
พร็อพเพอร์ตี้นี้ใช้สี colorPrimary
ที่กําหนดไว้ล่วงหน้าในแอป และใช้แต้มนั้นเพื่อไฮไลต์ไอคอนจักรยานและคืนค่าเป็น BitmapDescriptor
- ในการใช้พร็อพเพอร์ตี้นี้ ให้เรียกใช้เมธอด
icon
ของMarkerOptions
ในเมธอดaddMarkers()
เพื่อกําหนดค่าไอคอนด้วยตนเอง เมื่อทําเช่นนี้ พร็อพเพอร์ตี้ตัวทําเครื่องหมายควรมีลักษณะดังนี้
MainActivity.addMarkers()
val marker = googleMap.addMarker(
MarkerOptions()
.title(place.name)
.position(place.latLng)
.icon(bicycleIcon)
)
- เรียกใช้แอปเพื่อดูเครื่องหมายที่อัปเดตแล้ว
8. ตัวทําเครื่องหมายคลัสเตอร์
คุณอาจสังเกตเห็นว่าเครื่องหมายที่คุณเพิ่มซ้อนทับกัน ทั้งนี้ขึ้นอยู่กับระยะทางที่คุณซูมเข้าไปในแผนที่ ตัวทําเครื่องหมายที่ทับซ้อนกันนั้นโต้ตอบได้ยากและสร้างเสียงรบกวนจํานวนมาก ซึ่งส่งผลกระทบต่อความสามารถในการใช้งานของแอป
เพื่อปรับปรุงประสบการณ์ของผู้ใช้ให้ดียิ่งขึ้น เมื่อใดก็ตามที่คุณมีชุดข้อมูลขนาดใหญ่ที่รวมกันอยู่ใกล้กัน แนวทางปฏิบัติที่ดีที่สุดคือการนําคลัสเตอร์เครื่องหมายไปใช้ เมื่อใช้การจัดกลุ่ม เมื่อคุณซูมเข้าและออกในแผนที่ เครื่องหมายที่อยู่ในบริเวณใกล้เคียงจะกระจุกรวมกันอยู่เช่นนี้
ในการใช้งาน คุณต้องขอความช่วยเหลือจาก Maps SDK สําหรับไลบรารียูทิลิตีของ Android
Maps SDK สําหรับไลบรารียูทิลิตีของ Android
Maps SDK สําหรับ Android Utility Library สร้างขึ้นเป็นวิธีหนึ่งในการขยายฟังก์ชันการทํางานของ Maps SDK สําหรับ Android โดยมีฟีเจอร์ขั้นสูงต่างๆ เช่น คลัสเตอร์เครื่องหมาย ฮีตแมป KML และการรองรับ GeoJson การเข้ารหัสและถอดรหัส Polyline รวมถึงฟังก์ชันผู้ช่วยในรูปเรขาคณิต 360 องศาที่มีอยู่มากมาย
อัปเดต build.gradle
เนื่องจากไลบรารียูทิลิตีมีแพ็กเกจแยกต่างหากจาก Maps SDK สําหรับ Android คุณจึงต้องเพิ่มทรัพยากร Dependency ไปยังไฟล์ build.gradle
- อัปเดตส่วน
dependencies
ของไฟล์app/build.gradle
ได้เลย
build.gradle
implementation 'com.google.maps.android:android-maps-utils:1.1.0'
- เมื่อเพิ่มบรรทัดนี้ คุณจะต้องซิงค์โปรเจ็กต์เพื่อดึงข้อมูลทรัพยากร Dependency ใหม่
ใช้การจัดกลุ่ม
หากต้องการใช้การจัดกลุ่มในแอป ให้ทําตามขั้นตอน 3 ขั้นตอนต่อไปนี้
- ใช้อินเทอร์เฟซ
ClusterItem
- คลาสย่อย
DefaultClusterRenderer
- สร้าง
ClusterManager
แล้วเพิ่มรายการ
ใช้อินเทอร์เฟซ ClusterItem
ออบเจ็กต์ทั้งหมดที่แทนเครื่องหมายที่จัดกลุ่มได้บนแผนที่ต้องใช้อินเทอร์เฟซ ClusterItem
ในกรณีของคุณ นั่นหมายความว่ารูปแบบ Place
ต้องสอดคล้องกับ ClusterItem
ดําเนินการต่อและเปิดไฟล์ Place.kt
แล้วทําการแก้ไขต่อไปนี้
สถานที่
data class Place(
val name: String,
val latLng: LatLng,
val address: String,
val rating: Float
) : ClusterItem {
override fun getPosition(): LatLng =
latLng
override fun getTitle(): String =
name
override fun getSnippet(): String =
address
}
ClusterItem จะกําหนด 3 วิธีต่อไปนี้
getPosition()
ซึ่งแสดงถึงสถานที่LatLng
getTitle()
ซึ่งแสดงถึงชื่อสถานที่getSnippet()
ซึ่งแสดงถึงที่อยู่ของสถานที่
คลาสย่อย DefaultClusterRenderer
ชั้นเรียนที่รับผิดชอบการใช้งานคลัสเตอร์ ClusterManager
จะใช้คลาส ClusterRenderer
ภายในเพื่อจัดการการสร้างคลัสเตอร์ขณะที่เลื่อนและซูมแผนที่ โดยค่าเริ่มต้นจะมาพร้อมกับตัวแสดงผลเริ่มต้น DefaultClusterRenderer
ซึ่งใช้ ClusterRenderer
สําหรับขั้นตอนง่ายๆ วิธีนี้น่าจะเพียงพอ อย่างไรก็ตาม เนื่องจากจําเป็นต้องปรับแต่งเครื่องหมาย คุณจึงต้องขยายคลาสนี้และเพิ่มการปรับแต่งในส่วนนี้
ดําเนินการต่อและสร้างไฟล์ Kotlin PlaceRenderer.kt
ในแพ็กเกจ com.google.codelabs.buildyourfirstmap.place
แล้วกําหนดสิ่งต่อไปนี้
PlaceRenderer
package com.google.codelabs.buildyourfirstmap.place
import android.content.Context
import androidx.core.content.ContextCompat
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.Marker
import com.google.android.gms.maps.model.MarkerOptions
import com.google.codelabs.buildyourfirstmap.BitmapHelper
import com.google.codelabs.buildyourfirstmap.R
import com.google.maps.android.clustering.ClusterManager
import com.google.maps.android.clustering.view.DefaultClusterRenderer
/**
* A custom cluster renderer for Place objects.
*/
class PlaceRenderer(
private val context: Context,
map: GoogleMap,
clusterManager: ClusterManager<Place>
) : DefaultClusterRenderer<Place>(context, map, clusterManager) {
/**
* The icon to use for each cluster item
*/
private val bicycleIcon: BitmapDescriptor by lazy {
val color = ContextCompat.getColor(context,
R.color.colorPrimary
)
BitmapHelper.vectorToBitmap(
context,
R.drawable.ic_directions_bike_black_24dp,
color
)
}
/**
* Method called before the cluster item (the marker) is rendered.
* This is where marker options should be set.
*/
override fun onBeforeClusterItemRendered(
item: Place,
markerOptions: MarkerOptions
) {
markerOptions.title(item.name)
.position(item.latLng)
.icon(bicycleIcon)
}
/**
* Method called right after the cluster item (the marker) is rendered.
* This is where properties for the Marker object should be set.
*/
override fun onClusterItemRendered(clusterItem: Place, marker: Marker) {
marker.tag = clusterItem
}
}
คลาสนี้ลบล้างฟังก์ชัน 2 รายการต่อไปนี้
onBeforeClusterItemRendered()
ซึ่งจะเรียกใช้ก่อนที่กลุ่มจะแสดงผลบนแผนที่ คุณระบุการปรับแต่งผ่านMarkerOptions
ได้ ซึ่งในกรณีนี้คือการตั้งค่าชื่อ ตําแหน่ง และไอคอนของเครื่องหมายonClusterItemRenderer()
ซึ่งจะเรียกใช้ทันทีหลังจากแสดงเครื่องหมายบนแผนที่ นี่คือที่ที่คุณสามารถเข้าถึงออบเจ็กต์Marker
ที่สร้างขึ้น ซึ่งในกรณีนี้คือการตั้งค่าพร็อพเพอร์ตี้แท็กของเครื่องหมาย'
สร้าง ClusterManager และเพิ่มรายการ
สุดท้ายนี้ คุณจะต้องคลัสเตอร์ MainActivity
เพื่อแสดงตัวอย่าง ClusterManager
และให้ทรัพยากร Dependency ที่จําเป็นแก่คลัสเตอร์ ClusterManager
จะจัดการการเพิ่มเครื่องหมาย (วัตถุ ClusterItem
) ภายใน ดังนั้นแทนที่จะมอบหมายเครื่องหมายโดยตรงบนแผนที่ การมอบสิทธิ์นี้จึงมอบให้กับ ClusterManager
นอกจากนี้ ClusterManager
ยังเรียกใช้ setInfoWindowAdapter()
ภายในด้วย ดังนั้นการตั้งค่าหน้าต่างข้อมูลที่กําหนดเองจะต้องดําเนินการบนออบเจ็กต์ MarkerManager.Collection
ของ ClusterManger
'
- หากต้องการเริ่มใช้งาน ให้แก้ไขเนื้อหาของแลมบ์ดาในการเรียก
getMapAsync()
ในMainActivity.onCreate()
ดําเนินการต่อและแสดงความคิดเห็นในการโทรหาaddMarkers()
และsetInfoWindowAdapter()
และเรียกใช้เมธอดชื่อaddClusteredMarkers()
ซึ่งคุณกําหนดถัดไป
MainActivity.onCreate()
mapFragment?.getMapAsync { googleMap ->
//addMarkers(googleMap)
addClusteredMarkers(googleMap)
// Set custom info window adapter.
// googleMap.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))
}
- ต่อไปใน
MainActivity
ให้กําหนดaddClusteredMarkers()
MainActivity.addClusteredMarkers()
/**
* Adds markers to the map with clustering support.
*/
private fun addClusteredMarkers(googleMap: GoogleMap) {
// Create the ClusterManager class and set the custom renderer.
val clusterManager = ClusterManager<Place>(this, googleMap)
clusterManager.renderer =
PlaceRenderer(
this,
googleMap,
clusterManager
)
// Set custom info window adapter
clusterManager.markerCollection.setInfoWindowAdapter(MarkerInfoWindowAdapter(this))
// Add the places to the ClusterManager.
clusterManager.addItems(places)
clusterManager.cluster()
// Set ClusterManager as the OnCameraIdleListener so that it
// can re-cluster when zooming in and out.
googleMap.setOnCameraIdleListener {
clusterManager.onCameraIdle()
}
}
เมธอดนี้จะแจ้ง ClusterManager
ผ่านตัวแสดงผลที่กําหนดเอง PlacesRenderer
โดยเพิ่มสถานที่ทั้งหมด และเรียกใช้เมธอด cluster()
นอกจากนี้ เนื่องจาก ClusterManager
ใช้วิธีการของ setInfoWindowAdapter()
ในออบเจ็กต์แผนที่ ดังนั้นการตั้งค่าหน้าต่างข้อมูลที่กําหนดเองจึงต้องทําในออบเจ็กต์ ClusterManager.markerCollection
ข้อสุดท้าย เนื่องจากคุณต้องการให้คลัสเตอร์เปลี่ยนแปลงขณะที่ผู้ใช้เลื่อนและซูมรอบๆ แผนที่ จึงให้ OnCameraIdleListener
แก่ googleMap
ดังนั้นเมื่อกล้องไม่มีการใช้งาน clusterManager.onCameraIdle()
จะเรียกใช้
- ดําเนินการต่อและเรียกใช้แอปเพื่อดูร้านค้าใหม่ในคลัสเตอร์
9. วาดในแผนที่
ขณะที่คุณสํารวจวิธีการวาดบนแผนที่ (โดยการเพิ่มเครื่องหมาย) แล้ว Maps Maps สําหรับ Android จะรองรับวิธีการอื่นๆ ที่คุณวาดได้เพื่อแสดงข้อมูลที่เป็นประโยชน์บนแผนที่
ตัวอย่างเช่น หากคุณต้องการแสดงเส้นทางและพื้นที่บนแผนที่ คุณสามารถใช้รูปหลายเหลี่ยมและรูปหลายเหลี่ยมเพื่อแสดงข้อมูลเหล่านี้บนแผนที่ หรือหากต้องการแก้ไขรูปภาพในแพลตฟอร์มของพื้นดิน คุณใช้การวางซ้อนพื้นได้
ในงานนี้ คุณจะได้ดูวิธีวาดรูปร่าง โดยเฉพาะวงกลมรอบเครื่องหมายต่างๆ เมื่อแตะ
เพิ่ม Listener การคลิก
โดยปกติแล้ว วิธีเพิ่ม Listener การคลิกให้กับตัวทําเครื่องหมายคือการส่งผ่าน Listener การคลิกไปยังออบเจ็กต์ GoogleMap
โดยตรงผ่าน setOnMarkerClickListener()
อย่างไรก็ตาม เนื่องจากคุณกําลังใช้คลัสเตอร์ คุณจึงต้องฟัง Listener การคลิกไปยัง ClusterManager
แทน
- ในเมธอด
addClusteredMarkers()
ในMainActivity
ให้เพิ่มบรรทัดต่อไปนี้หลังจากส่งคําขอไปยังcluster()
แล้ว
MainActivity.addClusteredMarkers()
// Show polygon
clusterManager.setOnClusterItemClickListener { item ->
addCircle(googleMap, item)
return@setOnClusterItemClickListener false
}
เมธอดนี้จะเพิ่ม Listener และเรียกใช้เมธอด addCircle()
ซึ่งคุณจะกําหนดถัดไป ท้ายที่สุดแล้ว false
จะแสดงผลจากวิธีนี้เพื่อบ่งบอกว่าวิธีการนี้ไม่ได้ใช้เหตุการณ์นี้
- ต่อไปคุณต้องกําหนดพร็อพเพอร์ตี้
circle
และวิธีaddCircle()
ในMainActivity
MainActivity.addCircle()
private var circle: Circle? = null
/**
* Adds a [Circle] around the provided [item]
*/
private fun addCircle(googleMap: GoogleMap, item: Place) {
circle?.remove()
circle = googleMap.addCircle(
CircleOptions()
.center(item.latLng)
.radius(1000.0)
.fillColor(ContextCompat.getColor(this, R.color.colorPrimaryTranslucent))
.strokeColor(ContextCompat.getColor(this, R.color.colorPrimary))
)
}
ระบบได้ตั้งค่าพร็อพเพอร์ตี้ circle
แล้ว เมื่อใดก็ตามที่แตะเครื่องหมายใหม่ วงกลมก่อนหน้าจะถูกนําออกและเพิ่มวงกลมใหม่ลงไป โปรดสังเกตว่า API สําหรับการเพิ่มวงกลมจะคล้ายกับการเพิ่มเครื่องหมาย
- ดําเนินการต่อและเรียกใช้แอปเพื่อดูการเปลี่ยนแปลง
10. การควบคุมกล้อง
ในขั้นตอนสุดท้าย คุณจะดูการควบคุมกล้องบางส่วนเพื่อให้คุณสามารถโฟกัสมุมมองรอบๆ บางภูมิภาคได้
กล้องและมุมมอง
หากคุณสังเกตเห็นว่าแอปทํางานอยู่ กล้องถ่ายรูปจะแสดงทวีปแอฟริกา และต้องเลื่อนและซูมไปยังซานฟรานซิสโกอย่างน่าอัศจรรย์เพื่อค้นหาเครื่องหมายที่คุณเพิ่มไว้ แม้ว่าจะเป็นวิธีที่สนุกสนานในการสํารวจโลก แต่เครื่องมือนี้มีประโยชน์หากคุณต้องการแสดงเครื่องหมายโดยทันที
ในการช่วยนี้ คุณสามารถตั้งค่าตําแหน่งของกล้องแบบเป็นโปรแกรมเพื่อให้มุมมองอยู่ตรงกลางในตําแหน่งที่ต้องการ
- ดําเนินการต่อและเพิ่มโค้ดต่อไปนี้ลงในการเรียก
getMapAsync()
เพื่อปรับมุมมองกล้องเพื่อให้เริ่มต้นในซานฟรานซิสโกเมื่อมีการเปิดแอป
MainActivity.onCreate()
mapFragment?.getMapAsync { googleMap ->
// Ensure all places are visible in the map.
googleMap.setOnMapLoadedCallback {
val bounds = LatLngBounds.builder()
places.forEach { bounds.include(it.latLng) }
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))
}
}
ก่อนอื่นให้เรียกใช้ setOnMapLoadedCallback()
เพื่อให้การอัปเดตกล้องดําเนินการหลังจากที่โหลดแผนที่แล้วเท่านั้น ขั้นตอนนี้เป็นสิ่งจําเป็นเนื่องจากจําเป็นต้องคํานวณคุณสมบัติของแผนที่ เช่น มิติข้อมูล ก่อนที่จะเรียกใช้การอัปเดตกล้องถ่ายรูป
ในแลมบ์ดา ออบเจ็กต์ LatLngBounds
ใหม่จะสร้างขึ้นซึ่งจะกําหนดพื้นที่รูปสี่เหลี่ยมผืนผ้าบนแผนที่ ค่านี้ค่อยๆ เพิ่มโดยการรวมค่าสถานที่ LatLng
ทั้งหมดไว้ในค่านั้นเพื่อให้แน่ใจว่าสถานที่ทั้งหมดอยู่ภายในขอบเขต เมื่อสร้างออบเจ็กต์นี้แล้ว ระบบจะเรียกใช้เมธอด moveCamera()
ใน GoogleMap
และมีการระบุ CameraUpdate
ผ่าน CameraUpdateFactory.newLatLngBounds(bounds.build(), 20)
- เรียกใช้แอปและตรวจสอบว่ากล้องเริ่มต้นอยู่ในซานฟรานซิสโกแล้ว
กําลังฟังการเปลี่ยนแปลงจากกล้อง
นอกจากการปรับเปลี่ยนตําแหน่งกล้องแล้ว คุณยังฟังการอัปเดตของกล้องขณะที่ผู้ใช้เคลื่อนที่ไปรอบๆ แผนที่ได้ด้วย วิธีนี้อาจมีประโยชน์หากคุณต้องการแก้ไข UI เมื่อมีการขยับกล้อง
เพื่อความสนุกสนาน คุณแก้ไขโค้ดเพื่อให้เครื่องหมายโปร่งแสงทุกครั้งที่มีการย้ายกล้อง
- ในเมธอด
addClusteredMarkers()
ให้เพิ่มบรรทัดต่อไปนี้ที่ด้านล่างของเมธอด
MainActivity.addClusteredMarkers()
// When the camera starts moving, change the alpha value of the marker to translucent.
googleMap.setOnCameraMoveStartedListener {
clusterManager.markerCollection.markers.forEach { it.alpha = 0.3f }
clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 0.3f }
}
การดําเนินการนี้จะเพิ่ม OnCameraMoveStartedListener
เพื่อที่เมื่อใดก็ตามที่กล้องเริ่มเคลื่อนที่ ค่าเครื่องหมายทั้งหมด' (ทั้งคลัสเตอร์และเครื่องหมาย) จะปรับเปลี่ยนเป็น 0.3f
เพื่อให้ตัวทําเครื่องหมายโปร่งแสง
- สุดท้าย หากต้องการแก้ไขตัวทําเครื่องหมายโปร่งแสงให้กลับมาทึบเมื่อกล้องหยุด ให้แก้ไขเนื้อหาของ
setOnCameraIdleListener
ในเมธอดaddClusteredMarkers()
เป็นสิ่งต่อไปนี้
MainActivity.addClusteredMarkers()
googleMap.setOnCameraIdleListener {
// When the camera stops moving, change the alpha value back to opaque.
clusterManager.markerCollection.markers.forEach { it.alpha = 1.0f }
clusterManager.clusterMarkerCollection.markers.forEach { it.alpha = 1.0f }
// Call clusterManager.onCameraIdle() when the camera stops moving so that reclustering
// can be performed when the camera stops moving.
clusterManager.onCameraIdle()
}
- เริ่มเรียกใช้แอปเพื่อดูผลลัพธ์ได้เลย
11. แผนที่ KTX
สําหรับแอป Kotlin ที่ใช้ SDK สําหรับ Google Maps Platform สําหรับ Android ตั้งแต่ 1 รายการขึ้นไป ส่วนขยายของ Kotlin หรือไลบรารี KTX จะช่วยให้คุณใช้ประโยชน์จากฟีเจอร์ของภาษา Kotlin เช่น โครูทีน พร็อพเพอร์ตี้/ฟังก์ชันส่วนขยาย และอื่นๆ อีกมากมาย Google Maps SDK แต่ละรายการมีไลบรารี KTX ที่เกี่ยวข้องดังที่แสดงด้านล่าง
ในงานนี้ คุณจะได้ใช้ไลบรารี Maps KTX และ Maps Utils KTX ในแอปของคุณและปรับเปลี่ยนงานก่อนหน้านี้' ติดตั้งใช้งานเพื่อให้คุณใช้ฟีเจอร์ภาษาเฉพาะสําหรับ Kotlin ในแอปได้
- รวมทรัพยากร Dependency ของ KTX ในไฟล์ build.gradle ระดับแอป
เนื่องจากแอปใช้ทั้ง Maps SDK สําหรับ Android และ Maps SDK สําหรับ Android Utility Library คุณจะต้องรวมไลบรารี KTX ที่เกี่ยวข้องสําหรับไลบรารีเหล่านี้ด้วย คุณจะใช้ฟีเจอร์ที่พบในไลบรารี AndroidX Lifecycle KTX ในงานนี้ด้วย ดังนั้นโปรดรวมทรัพยากร Dependency ดังกล่าวไว้ในไฟล์ build.gradle
ระดับแอปด้วย
build.gradle
dependencies {
// ...
// Maps SDK for Android KTX Library
implementation 'com.google.maps.android:maps-ktx:3.0.0'
// Maps SDK for Android Utility Library KTX Library
implementation 'com.google.maps.android:maps-utils-ktx:3.0.0'
// Lifecycle Runtime KTX Library
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
}
- ใช้ฟังก์ชันส่วนขยายของ GoogleMaps.addMarker() และ GoogleMAP.addCircle()
ไลบรารี Maps KTX เป็นทางเลือกของ API แบบ DSL สําหรับ GoogleMap.addMarker(MarkerOptions)
และ GoogleMap.addCircle(CircleOptions)
ที่ใช้ในขั้นตอนก่อนหน้า หากต้องการใช้ API ที่กล่าวมาข้างต้น การสร้างชั้นเรียนที่มีตัวเลือกสําหรับเครื่องหมายหรือวงกลมนั้นเป็นสิ่งที่จําเป็น ในขณะที่ทางเลือกแบบ KTX ทําให้คุณสามารถตั้งค่าตัวเลือกเครื่องหมายหรือวงกลมในแลมบ์ดาที่คุณให้ไว้ได้
หากต้องการใช้ API เหล่านี้ ให้อัปเดตเมธอด MainActivity.addMarkers(GoogleMap)
และ MainActivity.addCircle(GoogleMap)
MainActivity.addMarkers(GoogleMaps)
/**
* Adds markers to the map. These markers won't be clustered.
*/
private fun addMarkers(googleMap: GoogleMap) {
places.forEach { place ->
val marker = googleMap.addMarker {
title(place.name)
position(place.latLng)
icon(bicycleIcon)
}
// Set place as the tag on the marker object so it can be referenced within
// MarkerInfoWindowAdapter
marker.tag = place
}
}
MainActivity.addCircle(GoogleMaps)
/**
* Adds a [Circle] around the provided [item]
*/
private fun addCircle(googleMap: GoogleMap, item: Place) {
circle?.remove()
circle = googleMap.addCircle {
center(item.latLng)
radius(1000.0)
fillColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimaryTranslucent))
strokeColor(ContextCompat.getColor(this@MainActivity, R.color.colorPrimary))
}
}
การเขียนเมธอดข้างต้นด้วยวิธีนี้จะช่วยให้อ่านได้ละเอียดขึ้นมากด้วยการใช้ฟังก์ชันลิเทอรัลที่มีตัวรับสัญญาณ จาก Kotlin
- ใช้ฟังก์ชันการระงับส่วนขยาย Support MapFragment.aWait Map() และ GoogleMAP.aWait MapLoad()
ไลบรารี Maps KTX มีส่วนขยายฟังก์ชันสําหรับระงับที่ใช้ร่วมกับโครูทีนด้วย นั่นคือมีการระงับฟังก์ชันสํารองสําหรับ SupportMapFragment.getMapAsync(OnMapReadyCallback)
และ GoogleMap.setOnMapLoadedCallback(OnMapLoadedCallback)
การใช้ API ทางเลือกเหล่านี้ทําให้ไม่จําเป็นต้องส่งโค้ดเรียกกลับและช่วยให้คุณได้รับการตอบสนองของเมธอดเหล่านี้แบบอนุกรมและซิงโครนัสแทน
เนื่องจากวิธีการเหล่านี้จะระงับฟังก์ชัน การใช้งานจึงต้องเกิดขึ้นภายในโครูทีน ไลบรารี Lifecycle Runtime KTX มีส่วนขยายที่ให้ขอบเขต Coroutine ที่คํานึงถึงวงจรการใช้งานเพื่อให้ Coroutine ทํางานและหยุดที่เหตุการณ์ในวงจรที่เหมาะสม
เมื่อรวมแนวคิดเหล่านี้ ให้อัปเดตเมธอด MainActivity.onCreate(Bundle)
:
MainActivity.onCreate(แพ็กเกจ)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mapFragment =
supportFragmentManager.findFragmentById(R.id.map_fragment) as SupportMapFragment
lifecycleScope.launchWhenCreated {
// Get map
val googleMap = mapFragment.awaitMap()
// Wait for map to finish loading
googleMap.awaitMapLoad()
// Ensure all places are visible in the map
val bounds = LatLngBounds.builder()
places.forEach { bounds.include(it.latLng) }
googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds.build(), 20))
addClusteredMarkers(googleMap)
}
}
ขอบเขต lifecycleScope.launchWhenCreated
โครูทีนจะเรียกใช้การบล็อกเมื่อกิจกรรมอยู่ในสถานะที่สร้างเป็นอย่างน้อย โปรดสังเกตว่าการเรียกเพื่อเรียกออบเจ็กต์ GoogleMap
และเพื่อรอให้แผนที่โหลดเสร็จจึงแทนที่ด้วย SupportMapFragment.awaitMap()
และ GoogleMap.awaitMapLoad()
ตามลําดับ การถอดรหัสโค้ดใหม่โดยใช้ฟังก์ชันการระงับเหล่านี้ช่วยให้คุณเขียนโค้ดตามโค้ดเรียกกลับที่เทียบเท่าได้ตามลําดับ
- เริ่มสร้างแอปอีกครั้งด้วยการเปลี่ยนแปลงของคุณ
12. ยินดีด้วย
ยินดีด้วย คุณได้อธิบายเนื้อหาไว้มากมายและหวังว่าคุณจะเข้าใจฟีเจอร์หลักที่มีใน Maps SDK สําหรับ Android ได้ดียิ่งขึ้น
ดูข้อมูลเพิ่มเติม
- SDK สถานที่สําหรับ Android สํารวจชุดข้อมูลสถานที่ที่สมบูรณ์เพื่อค้นพบธุรกิจรอบตัวคุณ
- android-maps-ktx เป็นไลบรารีแบบโอเพนซอร์สที่ให้คุณผสานรวมกับ Maps SDK สําหรับ Android และไลบรารี SDK ของ Maps สําหรับ Android Utility Library ในรูปแบบที่ใช้งานร่วมกับ Kotlin ได้
- android-place-ktx - ไลบรารีโอเพนซอร์สที่ให้คุณผสานรวมกับ Places SDK สําหรับ Android ด้วยวิธีที่เหมาะกับ Kotlin
- android-samples - โค้ดตัวอย่างใน GitHub ที่แสดงฟีเจอร์ทั้งหมดที่ครอบคลุมใน Codelab นี้และอื่นๆ
- Kotlin Codelabs เพิ่มเติมสําหรับการสร้างแอป Android ด้วย Google Maps Platform