Android ขั้นสูงใน Kotlin 04.1: Google Maps สำหรับ Android

1. ก่อนเริ่มต้น

การสร้างแอปด้วย Google Maps จะช่วยให้คุณเพิ่มฟีเจอร์ต่างๆ ลงในแอปได้ เช่น ภาพถ่ายจากดาวเทียม การควบคุม UI ที่มีประสิทธิภาพสำหรับแผนที่ การติดตามตำแหน่ง และเครื่องหมายระบุตำแหน่ง คุณสามารถเพิ่มคุณค่าให้กับ Google Maps มาตรฐานด้วยการแสดงข้อมูลจากชุดข้อมูลของคุณเอง เช่น สถานที่ตกปลาหรือพื้นที่ปีนเขาชื่อดัง คุณยังสร้างเกมที่ผู้เล่นสำรวจโลกจริงได้ด้วย เช่น ในเกมล่าสมบัติหรือแม้กระทั่งเกมเทคโนโลยีความจริงเสริม (AR)

ในบทเรียนนี้ คุณจะได้สร้างแอป Google Maps ชื่อ Wander ซึ่งแสดงแผนที่ที่กำหนดเองและแสดงตำแหน่งของผู้ใช้

ข้อกำหนดเบื้องต้น

ความรู้เกี่ยวกับสิ่งต่อไปนี้

  • วิธีสร้างแอป Android พื้นฐานและเรียกใช้โดยใช้ Android Studio
  • วิธีสร้างและจัดการทรัพยากร เช่น สตริง
  • วิธีเปลี่ยนโครงสร้างโค้ดและเปลี่ยนชื่อตัวแปรโดยใช้ Android Studio
  • วิธีใช้ Google Maps ในฐานะผู้ใช้
  • วิธีตั้งค่าสิทธิ์รันไทม์

สิ่งที่คุณจะได้เรียนรู้

  • วิธีรับคีย์ API จากคอนโซล Google API และลงทะเบียนคีย์กับแอปของคุณ
  • วิธีผสานรวม Google Maps ในแอปของคุณ
  • วิธีแสดงแผนที่ประเภทต่างๆ
  • วิธีจัดรูปแบบ Google Maps
  • วิธีเพิ่มเครื่องหมายลงในแผนที่ของคุณ
  • วิธีทำให้ผู้ใช้สามารถวางเครื่องหมายบนจุดที่น่าสนใจ (POI) ได้
  • วิธีเปิดใช้การติดตามตำแหน่ง
  • วิธีสร้างแอป Wander ซึ่งมี Google Maps ฝังอยู่
  • วิธีสร้างฟีเจอร์ที่กำหนดเองให้กับแอป เช่น เครื่องหมายและการจัดรูปแบบ
  • วิธีเปิดใช้การติดตามตำแหน่งในแอปของคุณ

2. ภาพรวมของแอป

ใน Codelab นี้ คุณจะได้สร้างแอป Wander ซึ่งจะแสดงแผนที่ Google พร้อมการจัดรูปแบบที่กำหนดเอง แอป Wander ให้คุณวางเครื่องหมายลงบนตำแหน่ง เพิ่มการวางซ้อน และดูตำแหน่งของคุณในแบบเรียลไทม์

5b12eda7f467bc2f.png

3. งาน: ตั้งค่าโปรเจ็กต์และรับคีย์ API

Maps SDK สำหรับ Android ต้องใช้คีย์ API หากต้องการรับคีย์ API ให้ลงทะเบียนโปรเจ็กต์ใน API และ หน้าบริการ คีย์ API ผูกกับใบรับรองดิจิทัลที่ลิงก์แอปกับผู้เขียน โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ใบรับรองดิจิทัลและการลงนามแอปที่หัวข้อลงนามแอป

ใน Codelab นี้ คุณใช้คีย์ API สำหรับใบรับรองการแก้ไขข้อบกพร่อง ใบรับรองการแก้ไขข้อบกพร่องออกแบบมาให้ไม่ปลอดภัย ตามที่อธิบายไว้ในลงนามบิลด์การแก้ไขข้อบกพร่อง แอป Android ที่เผยแพร่แล้วที่ใช้ Maps SDK สำหรับ Android ต้องใช้คีย์ API ที่สอง ซึ่งเป็นคีย์สำหรับใบรับรองรุ่น โปรดดูข้อมูลเพิ่มเติมเกี่ยวกับการรับใบรับรองรุ่นที่หัวข้อรับคีย์ API

Android Studio มีเทมเพลตกิจกรรมใน Google Maps ซึ่งจะสร้างโค้ดเทมเพลตที่เป็นประโยชน์ โค้ดเทมเพลตประกอบด้วยไฟล์ google_maps_api.xml ที่มีลิงก์ซึ่งช่วยให้รับคีย์ API ได้ง่ายขึ้น

ขั้นตอนที่ 1: สร้างโปรเจ็กต์ Wander ด้วยเทมเพลตแผนที่

  1. สร้างโปรเจ็กต์ Android Studio ใหม่
  2. เลือกเทมเพลตกิจกรรมใน Google Maps

d6b874bb19ea68cd.png

  1. ตั้งชื่อโปรเจ็กต์ Wander
  2. ตั้งค่าระดับ API ขั้นต่ำเป็น API 19 ตรวจสอบว่าภาษาคือ Kotlin
  3. คลิกเสร็จสิ้น
  4. เมื่อสร้างแอปเสร็จแล้ว ให้ตรวจสอบโปรเจ็กต์และไฟล์ที่เกี่ยวข้องกับแผนที่ต่อไปนี้ซึ่ง Android Studio สร้างให้คุณ

google_maps_api.xml - คุณใช้ไฟล์การกำหนดค่านี้เพื่อเก็บรักษาคีย์ API เทมเพลตจะสร้างไฟล์ google_maps_api.xml 2 ไฟล์ โดยไฟล์หนึ่งสำหรับแก้ไขข้อบกพร่องและอีกไฟล์หนึ่งสำหรับการเผยแพร่ ไฟล์ของคีย์ API สำหรับใบรับรองการแก้ไขข้อบกพร่องอยู่ใน src/debug/res/values ไฟล์ของคีย์ API สำหรับใบรับรองการเผยแพร่จะอยู่ใน src/release/res/values ใน Codelab นี้ คุณจะใช้เฉพาะใบรับรองการแก้ไขข้อบกพร่องเท่านั้น

activity_maps.xml - ไฟล์เลย์เอาต์นี้มีส่วนย่อยเดียวที่แสดงเต็มหน้าจอ คลาส SupportMapFragment เป็นคลาสย่อยของคลาส Fragment SupportMapFragment เป็นวิธีที่ง่ายที่สุดในการวางแผนที่ในแอป ซึ่งเป็น Wrapper ในการดูแผนที่เพื่อจัดการกับความต้องการที่จำเป็นในวงจรโดยอัตโนมัติ

คุณรวม SupportMapFragment ในไฟล์เลย์เอาต์ได้โดยใช้แท็ก <fragment> ใน ViewGroup ใดก็ได้โดยมีแอตทริบิวต์ name เพิ่มเติม

android:name="com.google.android.gms.maps.SupportMapFragment"

MapsActivity.java ไฟล์ MapsActivity.java จะสร้าง SupportMapFragment ในเมธอด onCreate() และใช้คลาส getMapAsync() เพื่อเริ่มต้นระบบแผนที่และมุมมองโดยอัตโนมัติ กิจกรรมที่มี SupportMapFragment ต้องใช้อินเทอร์เฟซ OnMapReadyCallback และวิธี onMapReady() ของอินเทอร์เฟซนั้น ระบบจะเรียกเมธอด onMapReady() เมื่อโหลดแผนที่

ขั้นตอนที่ 2: รับคีย์ API

  1. เปิดไฟล์ google_maps_api.xml เวอร์ชันที่แก้ไขข้อบกพร่อง
  2. ในไฟล์ ให้ค้นหาความคิดเห็นที่มี URL ยาว พารามิเตอร์ของ URL มีข้อมูลเฉพาะเกี่ยวกับแอปของคุณ
  3. คัดลอกและวาง URL ลงในเบราว์เซอร์
  4. ทำตามข้อความแจ้งเพื่อสร้างโปรเจ็กต์ใน API และ หน้าบริการ เนื่องจากพารามิเตอร์ใน URL ที่ระบุ หน้าเว็บจึงรู้ว่าจะต้องเปิดใช้ Maps SDK สำหรับ Android โดยอัตโนมัติ
  5. คลิกสร้างคีย์ API
  6. ในหน้าถัดไป ให้ไปที่ส่วนคีย์ API แล้วคลิกคีย์ที่คุณเพิ่งสร้างขึ้น
  7. คลิกจำกัดคีย์ แล้วเลือก Maps SDK สำหรับ Android เพื่อจำกัดการใช้คีย์สำหรับแอป Android
  8. คัดลอกคีย์ API ที่สร้างขึ้น โดยขึ้นต้นด้วย "AIza"
  9. ในไฟล์ google_maps_api.xml ให้วางคีย์ลงในสตริง google_maps_key ในตำแหน่งที่เขียนว่า YOUR_KEY_HERE
  10. เรียกใช้แอป คุณควรจะเห็นแผนที่ที่ฝังไว้ในกิจกรรมพร้อมกับเครื่องหมายที่ตั้งค่าในซิดนีย์ ออสเตรเลีย (เครื่องหมายซิดนีย์เป็นส่วนหนึ่งของเทมเพลตและคุณเปลี่ยนแปลงได้ในภายหลัง)

34dc9dd877c90996.png

ขั้นตอนที่ 3: เปลี่ยนชื่อ mMap

MapsActivity มี lateinit var ส่วนตัวชื่อว่า mMap ซึ่งเป็นประเภท GoogleMap หากต้องการตั้งชื่อ Kotlin ให้เปลี่ยนชื่อ mMap เป็น map

  1. ใน MapsActivity ให้คลิกขวาที่ mMap แล้วคลิกเปลี่ยนโครงสร้างภายใน > เปลี่ยนชื่อ...

e713ccb3384450c6.png

  1. เปลี่ยนชื่อตัวแปรเป็น map

สังเกตว่าการอ้างอิงถึง mMap ทั้งหมดในฟังก์ชัน onMapReady() เปลี่ยนเป็น map ด้วย

4. งาน: เพิ่มประเภทแผนที่

Google Maps มีแผนที่หลายประเภท ได้แก่ ปกติ ไฮบริด ดาวเทียม ภูมิประเทศ และ "ไม่มี" (หากไม่มีแผนที่เลย)

แผนที่ปกติ

แผนที่ดาวเทียม

แผนที่แบบผสม

แผนที่ภูมิประเทศ

แผนที่แต่ละประเภทให้ข้อมูลแตกต่างกัน ตัวอย่างเช่น เมื่อคุณใช้แผนที่สำหรับการนำทางในรถยนต์ การดูชื่อถนนจะมีประโยชน์เพื่อให้สามารถใช้ตัวเลือกปกติได้ เมื่อคุณกำลังเดินป่า แผนที่ภูมิประเทศอาจมีประโยชน์ในการตัดสินใจว่าคุณต้องปีนขึ้นอีกเท่าใดจึงจะถึงจุดสูงสุด

ในงานนี้ คุณจะทำสิ่งต่อไปนี้ได้

  1. เพิ่มแถบแอปด้วยเมนูตัวเลือกที่ให้ผู้ใช้เปลี่ยนประเภทแผนที่ได้
  2. ย้ายตำแหน่งเริ่มต้นของแผนที่ไปยังตำแหน่งบ้านของคุณเอง
  3. เพิ่มการรองรับเครื่องหมายซึ่งระบุสถานที่แห่งเดียวบนแผนที่และใส่ป้ายกำกับได้

เพิ่มเมนูสำหรับประเภทแผนที่

ในขั้นตอนนี้ คุณจะเพิ่มแถบแอปด้วยเมนูตัวเลือกที่ให้ผู้ใช้เปลี่ยนประเภทแผนที่ได้

  1. หากต้องการสร้างไฟล์ XML ของเมนูใหม่ ให้คลิกขวาที่ไดเรกทอรี res แล้วเลือกใหม่ > ไฟล์ทรัพยากร Android
  2. ตั้งชื่อไฟล์ในกล่องโต้ตอบว่า map_options
  3. เลือกเมนูสำหรับประเภททรัพยากร
  4. คลิกตกลง
  5. ในแท็บโค้ด ให้แทนที่โค้ดในไฟล์ใหม่ด้วยโค้ดต่อไปนี้เพื่อสร้างตัวเลือกเมนูแผนที่ คอลัมน์ "none" ไม่แสดงประเภทแผนที่เนื่องจาก "ไม่มี" ทำให้ไม่มีแผนที่ใดเลย การดำเนินการนี้จะทำให้เกิดข้อผิดพลาด แต่คุณจะแก้ไขได้ในขั้นตอนถัดไป
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:app="http://schemas.android.com/apk/res-auto">
   <item
       android:id="@+id/normal_map"
       android:title="@string/normal_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/hybrid_map"
       android:title="@string/hybrid_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/satellite_map"
       android:title="@string/satellite_map"
       app:showAsAction="never" />
   <item
       android:id="@+id/terrain_map"
       android:title="@string/terrain_map"
       app:showAsAction="never" />
</menu>
  1. ใน strings.xml ให้เพิ่มทรัพยากรสำหรับแอตทริบิวต์ title เพื่อแก้ไขข้อผิดพลาด
<resources>
   ...
   <string name="normal_map">Normal Map</string>
   <string name="hybrid_map">Hybrid Map</string>
   <string name="satellite_map">Satellite Map</string>
   <string name="terrain_map">Terrain Map</string>
   <string name="lat_long_snippet">Lat: %1$.5f, Long: %2$.5f</string>
   <string name="dropped_pin">Dropped Pin</string>
   <string name="poi">poi</string>
</resources>
  1. ใน MapsActivity ให้ลบล้างเมธอด onCreateOptionsMenu() และทำให้เมนูเพิ่มขึ้นจากไฟล์ทรัพยากร map_options
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
   val inflater = menuInflater
   inflater.inflate(R.menu.map_options, menu)
   return true
}
  1. ใน MapsActivity.kt ให้ลบล้างเมธอด onOptionsItemSelected() เปลี่ยนประเภทแผนที่โดยใช้ค่าคงที่ของประเภทแผนที่เพื่อแสดงการเลือกของผู้ใช้
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
   // Change the map type based on the user's selection.
   R.id.normal_map -> {
       map.mapType = GoogleMap.MAP_TYPE_NORMAL
       true
   }
   R.id.hybrid_map -> {
       map.mapType = GoogleMap.MAP_TYPE_HYBRID
       true
   }
   R.id.satellite_map -> {
       map.mapType = GoogleMap.MAP_TYPE_SATELLITE
       true
   }
   R.id.terrain_map -> {
       map.mapType = GoogleMap.MAP_TYPE_TERRAIN
       true
   }
   else -> super.onOptionsItemSelected(item)
}
  1. เรียกใช้แอป
  2. คลิก 428da163b831115b.png เพื่อเปลี่ยนประเภทแผนที่ โปรดสังเกตว่าลักษณะที่ปรากฏของแผนที่เปลี่ยนแปลงไประหว่างโหมดต่างๆ

6fa42970d87f5dc7.png

5. งาน: เพิ่มเครื่องหมาย

โดยค่าเริ่มต้น การเรียกกลับของ onMapReady() จะมีโค้ดที่วางเครื่องหมายในซิดนีย์ ออสเตรเลีย ซึ่งเป็นสถานที่สร้าง Google Maps การเรียกกลับเริ่มต้นยังจะแสดงภาพเคลื่อนไหวของแผนที่เพื่อเลื่อนไปที่ซิดนีย์ด้วย

ในงานนี้ คุณจะได้ทำให้กล้องของแผนที่ย้ายไปที่บ้านของคุณ ซูมถึงระดับที่คุณกำหนด และวางเครื่องหมายไว้ที่นั่น

ขั้นตอนที่ 1: ซูมไปที่บ้านและเพิ่มเครื่องหมาย

  1. ค้นหาเมธอด onMapReady() ในไฟล์ MapsActivity.kt ลบรหัสที่อยู่ในนั้นซึ่งวางเครื่องหมายไว้ในซิดนีย์แล้วย้ายกล้อง นี่คือหน้าตาวิธีการของคุณในปัจจุบัน
override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

}
  1. ค้นหาละติจูดและลองจิจูดของบ้านโดยทำตามวิธีการเหล่านี้
  2. สร้างค่าสำหรับละติจูดและค่าสำหรับลองจิจูด และป้อนค่าลอยตัว
val latitude = 37.422160
val longitude = -122.084270
  1. สร้างออบเจ็กต์ LatLng ใหม่ชื่อ homeLatLng ส่งค่าที่คุณเพิ่งสร้างขึ้นในออบเจ็กต์ homeLatLng
val homeLatLng = LatLng(latitude, longitude)
  1. สร้าง val ตามขนาดการซูมเข้าที่คุณต้องการให้แสดงบนแผนที่ ใช้ระดับการซูม 15f
val zoomLevel = 15f

ระดับการซูมจะควบคุมการซูมเข้าของคุณบนแผนที่ รายการต่อไปนี้จะแสดงรายละเอียดระดับของการซูมแต่ละระดับ

  • 1: โลก
  • 5: ผืนดินขนาดใหญ่/ทวีป
  • 10: เมือง
  • 15: ถนน
  • 20: อาคาร
  1. ย้ายกล้องไปที่ homeLatLng โดยเรียกใช้ฟังก์ชัน moveCamera() ในออบเจ็กต์ map แล้วส่งวัตถุ CameraUpdate โดยใช้ CameraUpdateFactory.newLatLngZoom() ส่งผ่านออบเจ็กต์ homeLatLng และ zoomLevel
map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
  1. เพิ่มเครื่องหมายลงในแผนที่ที่ homeLatLng
map.addMarker(MarkerOptions().position(homeLatLng))

วิธีการสุดท้ายควรมีลักษณะดังนี้

override fun onMapReady(googleMap: GoogleMap) {
   map = googleMap

   //These coordinates represent the latitude and longitude of the Googleplex.
   val latitude = 37.422160
   val longitude = -122.084270
   val zoomLevel = 15f

   val homeLatLng = LatLng(latitude, longitude)
   map.moveCamera(CameraUpdateFactory.newLatLngZoom(homeLatLng, zoomLevel))
   map.addMarker(MarkerOptions().position(homeLatLng))
}
  1. เรียกใช้แอป แผนที่ควรจะเลื่อนไปยังบ้านของคุณ ซูมไปที่ระดับที่ต้องการ และวางเครื่องหมายไว้บนบ้านของคุณ

fc939024778ee76.png

ขั้นตอนที่ 2: อนุญาตให้ผู้ใช้เพิ่มเครื่องหมายโดยการคลิกค้าง

ในขั้นตอนนี้ คุณจะเพิ่มเครื่องหมายเมื่อผู้ใช้แตะและค้างไว้ตำแหน่งบนแผนที่

  1. สร้างสตับเมธอดใน MapsActivity ชื่อ setMapLongClick() ที่จะนำ GoogleMap เป็นอาร์กิวเมนต์
  2. แนบ Listener setOnMapLongClickListener กับออบเจ็กต์แผนที่
private fun setMapLongClick(map:GoogleMap) {
   map.setOnMapLongClickListener { }
}
  1. ใน setOnMapLongClickListener() เรียกใช้เมธอด addMarker() ส่งผ่านออบเจ็กต์ MarkerOptions ใหม่ที่มีการตั้งค่าตำแหน่งเป็น LatLng ที่ส่งผ่าน
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. ในตอนท้ายของเมธอด onMapReady() ให้เรียก setMapLongClick() ด้วย map
override fun onMapReady(googleMap: GoogleMap) {
   ...
  
   setMapLongClick(map)
}
  1. เรียกใช้แอป
  2. แตะแผนที่ค้างไว้เพื่อวางเครื่องหมายที่ตำแหน่งใดตำแหน่งหนึ่ง
  3. แตะเครื่องหมายซึ่งกำหนดให้อยู่กึ่งกลางของหน้าจอ

4ff8d1c1db3bca9e.png

ขั้นตอนที่ 3: เพิ่มหน้าต่างข้อมูลสำหรับเครื่องหมาย

ในขั้นตอนนี้ คุณต้องเพิ่ม InfoWindow ที่แสดงพิกัดของเครื่องหมายเมื่อแตะเครื่องหมาย

  1. ใน setMapLongClick()setOnMapLongClickListener() ให้สร้าง val สำหรับ snippet ตัวอย่างคือข้อความเพิ่มเติมที่แสดงหลังชื่อ ข้อมูลโค้ดจะแสดงละติจูดและลองจิจูดของเครื่องหมาย
private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A snippet is additional text that's displayed after the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
       )
   }
}
  1. ใน addMarker() ให้ตั้งค่า title ของเครื่องหมายเป็น "มีการปักหมุด" โดยใช้ทรัพยากรสตริง R.string.dropped_pin
  2. กำหนด snippet ของเครื่องหมายเป็น snippet

ฟังก์ชันที่สมบูรณ์แล้วจะมีลักษณะดังนี้

private fun setMapLongClick(map: GoogleMap) {
   map.setOnMapLongClickListener { latLng ->
       // A Snippet is Additional text that's displayed below the title.
       val snippet = String.format(
           Locale.getDefault(),
           "Lat: %1$.5f, Long: %2$.5f",
           latLng.latitude,
           latLng.longitude
       )
       map.addMarker(
           MarkerOptions()
               .position(latLng)
               .title(getString(R.string.dropped_pin))
               .snippet(snippet)
              
       )
   }
}
  1. เรียกใช้แอป
  2. แตะแผนที่ค้างไว้เพื่อวางเครื่องหมายระบุตำแหน่ง
  3. แตะเครื่องหมายเพื่อแสดงหน้าต่างข้อมูล

63f210e6e47dfa29.png

ขั้นตอนที่ 4: เพิ่ม Listener จุดที่น่าสนใจ

โดยค่าเริ่มต้น จุดที่น่าสนใจ (POI) จะปรากฏบนแผนที่พร้อมกับไอคอนที่สอดคล้องกัน จุดที่น่าสนใจ ได้แก่ สวนสาธารณะ โรงเรียน อาคารหน่วยงานราชการ และอื่นๆ เมื่อตั้งประเภทแผนที่เป็น normal จุดที่น่าสนใจของธุรกิจก็จะปรากฏในแผนที่ด้วย จุดที่น่าสนใจของธุรกิจแสดงถึงธุรกิจต่างๆ เช่น ร้านค้า ร้านอาหาร และโรงแรม

ในขั้นตอนนี้ คุณต้องเพิ่ม GoogleMap.OnPoiClickListener ลงในแผนที่ Listener การคลิกนี้จะวางเครื่องหมายบนแผนที่ทันทีเมื่อผู้ใช้คลิกจุดที่น่าสนใจ Listener การคลิกจะแสดงหน้าต่างข้อมูลที่มีชื่อจุดที่น่าสนใจด้วย

  1. สร้างสตับเมธอดใน MapsActivity ชื่อ setPoiClick() ที่จะนำ GoogleMap เป็นอาร์กิวเมนต์
  2. ในเมธอด setPoiClick() ให้ตั้งค่า OnPoiClickListener ใน GoogleMap ที่ส่งผ่าน
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->

   }
}
  1. ใน setOnPoiClickListener() ให้สร้าง val poiMarker สำหรับเครื่องหมาย
  2. ตั้งค่าเป็นเครื่องหมายโดยใช้ map.addMarker() พร้อมกับ MarkerOptions ให้ตั้งค่า title เป็นชื่อของจุดที่น่าสนใจ
private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
   }
}
  1. ในฟังก์ชัน setOnPoiClickListener() ให้เรียกใช้ showInfoWindow() ใน poiMarker เพื่อแสดงหน้าต่างข้อมูลทันที
poiMarker.showInfoWindow()

โค้ดสุดท้ายของฟังก์ชัน setPoiClick() ควรมีลักษณะดังนี้

private fun setPoiClick(map: GoogleMap) {
   map.setOnPoiClickListener { poi ->
       val poiMarker = map.addMarker(
           MarkerOptions()
               .position(poi.latLng)
               .title(poi.name)
       )
       poiMarker.showInfoWindow()
   }
}
  1. เมื่อสิ้นเวลา onMapReady() ให้โทรหา setPoiClick() และผ่านใน map
override fun onMapReady(googleMap: GoogleMap) {
   ...

   setPoiClick(map)
}
  1. เรียกใช้แอปและค้นหาจุดที่น่าสนใจ เช่น สวนสาธารณะหรือร้านกาแฟ
  2. แตะจุดที่น่าสนใจเพื่อวางเครื่องหมายและแสดงชื่อจุดที่น่าสนใจในหน้าต่างข้อมูล

f4b0972c75d5fa5f.png

6. งาน: จัดรูปแบบแผนที่

คุณสามารถปรับแต่ง Google Maps ได้หลายวิธี ทำให้แผนที่ของคุณมีรูปลักษณ์ที่ไม่ซ้ำใคร

คุณสามารถปรับแต่งออบเจ็กต์ MapFragment โดยใช้แอตทริบิวต์ XML ที่มีอยู่ได้ เช่นเดียวกับการปรับแต่งส่วนย่อยอื่นๆ แต่ในขั้นตอนนี้ คุณจะปรับแต่งรูปลักษณ์ของเนื้อหาของ MapFragment โดยใช้เมธอดในออบเจ็กต์ GoogleMap

หากต้องการสร้างรูปแบบที่กำหนดเองสำหรับแผนที่ คุณต้องสร้างไฟล์ JSON ที่ระบุวิธีแสดงสถานที่ในแผนที่ คุณไม่จำเป็นต้องสร้างไฟล์ JSON นี้ด้วยตนเอง Google มีวิซาร์ดการจัดรูปแบบแพลตฟอร์ม Maps ซึ่งจะสร้าง JSON ให้คุณหลังจากที่คุณจัดรูปแบบแผนที่แล้ว ในงานนี้ คุณได้จัดรูปแบบแผนที่ด้วยธีมย้อนยุค ซึ่งหมายความว่าแผนที่จะใช้สีย้อนยุคและคุณได้เพิ่มถนนสีต่างๆ

ขั้นตอนที่ 1: สร้างรูปแบบสำหรับแผนที่ของคุณ

  1. ไปที่ https://mapstyle.withgoogle.com/ ในเบราว์เซอร์
  2. เลือกสร้างรูปแบบ
  3. เลือกย้อนยุค

208b3d3aeab0d9b6.png

  1. คลิกตัวเลือกเพิ่มเติม

4a35faaf9535ee82

  1. เลือกถนน > เติม
  2. เปลี่ยนสีของถนนเป็นสีที่คุณเลือก (เช่น สีชมพู)

92c3293749293a4c.png

  1. คลิกเสร็จสิ้น

f1bfe8585eb69480.png

  1. คัดลอกโค้ด JSON จากกล่องโต้ตอบที่ปรากฏขึ้น และเก็บไว้ในโน้ตข้อความธรรมดาเพื่อใช้ในขั้นตอนถัดไป หากต้องการ

3c32168b299d6420.png

ขั้นตอนที่ 2: เพิ่มรูปแบบลงในแผนที่

  1. ใน Android Studio ให้สร้างไดเรกทอรีทรัพยากรและตั้งชื่อไดเรกทอรี res raw คุณใช้ทรัพยากรไดเรกทอรี raw เช่น โค้ด JSON
  2. สร้างไฟล์ใน res/raw ชื่อ map_style.json
  3. วางโค้ด JSON ที่ซ่อนลงในไฟล์ทรัพยากรใหม่
  4. ใน MapsActivity ให้สร้างตัวแปรคลาส TAG เหนือเมธอด onCreate() ซึ่งใช้สำหรับการบันทึก
private val TAG = MapsActivity::class.java.simpleName
  1. และใน MapsActivity ให้สร้างฟังก์ชัน setMapStyle() ที่จะเข้า GoogleMap ด้วย
  2. ใน setMapStyle() ให้เพิ่มบล็อก try{}
  3. ในบล็อก try{} ให้สร้าง val success เพื่อให้การจัดรูปแบบสำเร็จ (คุณได้เพิ่มบล็อคคำสั่งต่อไปนี้)
  4. ในบล็อก try{} ให้ตั้งค่ารูปแบบ JSON ให้กับแผนที่ เรียก setMapStyle() ในออบเจ็กต์ GoogleMap ส่งออบเจ็กต์ MapStyleOptions ซึ่งจะโหลดไฟล์ JSON
  5. กำหนดผลลัพธ์ให้กับ success เมธอด setMapStyle() จะแสดงค่าบูลีนที่ระบุสถานะสำเร็จในการแยกวิเคราะห์ไฟล์การจัดรูปแบบและการตั้งค่ารูปแบบ
private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )
   }
}
  1. เพิ่มคำสั่ง if สำหรับ success ซึ่งเป็นเท็จ หากการจัดรูปแบบไม่สำเร็จ ให้พิมพ์บันทึกที่การแยกวิเคราะห์ล้มเหลว
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   }
}
  1. เพิ่มบล็อก catch{} เพื่อจัดการกับสถานการณ์ของไฟล์รูปแบบที่หายไป ในบล็อก catch หากโหลดไฟล์ไม่ได้ ให้ส่ง Resources.NotFoundException
private fun setMapStyle(map: GoogleMap) {
   try {
       ...
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}

วิธีการที่เสร็จแล้วควรมีลักษณะเหมือนข้อมูลโค้ดต่อไปนี้

private fun setMapStyle(map: GoogleMap) {
   try {
       // Customize the styling of the base map using a JSON object defined
       // in a raw resource file.
       val success = map.setMapStyle(
           MapStyleOptions.loadRawResourceStyle(
               this,
               R.raw.map_style
           )
       )

       if (!success) {
           Log.e(TAG, "Style parsing failed.")
       }
   } catch (e: Resources.NotFoundException) {
       Log.e(TAG, "Can't find style. Error: ", e)
   }
}
  1. สุดท้าย เรียกใช้เมธอด setMapStyle() ในการส่งเมธอด onMapReady() ในออบเจ็กต์ GoogleMap ของคุณ
override fun onMapReady(googleMap: GoogleMap) {
   ...
   setMapStyle(map)
}
  1. เรียกใช้แอป
  2. ตั้งแผนที่เป็นโหมด normal และรูปแบบใหม่ควรมองเห็นได้พร้อมธีมย้อนยุคและถนนสีที่คุณเลือก

b59d6cb81f02a14f.png

ขั้นตอนที่ 3: จัดรูปแบบเครื่องหมาย

คุณสามารถปรับเปลี่ยนแผนที่ในแบบของคุณเพิ่มเติมโดยจัดรูปแบบเครื่องหมายบนแผนที่ ในขั้นตอนนี้ คุณจะได้เปลี่ยนเครื่องหมายสีแดงเริ่มต้นให้มีความน่าสนใจยิ่งขึ้น

  1. ในเมธอด onMapLongClick() ให้เพิ่มบรรทัดโค้ดต่อไปนี้ลงใน MarkerOptions() ของเครื่องมือสร้างเพื่อใช้เครื่องหมายเริ่มต้น แต่เปลี่ยนสีเป็นสีน้ำเงิน
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))

ตอนนี้ onMapLongClickListener() จะมีหน้าตาแบบนี้:

map.setOnMapLongClickListener { latLng ->
   // A snippet is additional text that's displayed after the title.
   val snippet = String.format(
       Locale.getDefault(),
       "Lat: %1$.5f, Long: %2$.5f",
       latLng.latitude,
       latLng.longitude
   )
   map.addMarker(
       MarkerOptions()
           .position(latLng)
           .title(getString(R.string.dropped_pin))
           .snippet(snippet)
         .icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_BLUE))
   )
}
  1. เรียกใช้แอป เครื่องหมายที่ปรากฏหลังจากคลิกค้างจะเปลี่ยนเป็นสีน้ำเงิน โปรดทราบว่าเครื่องหมายจุดที่น่าสนใจยังคงเป็นสีแดงเนื่องจากคุณไม่ได้เพิ่มการจัดรูปแบบให้กับเมธอด onPoiClick()

b9916bca3c367e3.png

7. งาน: เพิ่มการวางซ้อน

วิธีหนึ่งที่คุณจะปรับแต่ง Google Maps ได้คือการวาดทับแผนที่นั้น เทคนิคนี้จะเป็นประโยชน์หากคุณต้องการเน้นสถานที่ตั้งประเภทใดประเภทหนึ่ง เช่น จุดตกปลายอดนิยม

  • รูปร่าง: คุณสามารถเพิ่มรูปหลายเหลี่ยม รูปหลายเหลี่ยม และวงกลมลงในแผนที่
  • GroundOverlay วัตถุ: การวางซ้อนพื้นคือรูปภาพที่ถูกยึดไว้กับแผนที่ การวางซ้อนพื้นจะแตกต่างจากเครื่องหมายตรงตำแหน่งพื้นผิวของโลก ไม่ใช่บนหน้าจอ การหมุน เอียง หรือซูมแผนที่จะเปลี่ยนการวางแนวของรูปภาพ การวางซ้อนภาคพื้นดินมีประโยชน์เมื่อคุณต้องการแก้ไขรูปภาพหนึ่งภาพในบริเวณใดบริเวณหนึ่งบนแผนที่

ขั้นตอน: เพิ่มการวางซ้อนพื้น

ในงานนี้ คุณจะได้เพิ่มพื้นดินเป็นรูปตัว Android ลงในตำแหน่งบ้านของคุณ

  1. ดาวน์โหลด รูปภาพ Android นี้ และบันทึกไว้ในโฟลเดอร์ res/drawable ของคุณ (ตรวจสอบว่าชื่อไฟล์คือ android.png)

61fabd56a0841b44.png

  1. ใน onMapReady() หลังจากเรียกใช้ให้ย้ายกล้องไปยังตำแหน่งของบ้านแล้ว ให้สร้างวัตถุ GroundOverlayOptions
  2. กำหนดออบเจ็กต์ให้กับตัวแปรที่ชื่อ androidOverlay
val androidOverlay = GroundOverlayOptions()
  1. ใช้เมธอด BitmapDescriptorFactory.fromResource() เพื่อสร้างออบเจ็กต์ BitmapDescriptor จากทรัพยากรรูปภาพที่ดาวน์โหลดมา
  2. ส่งผ่านออบเจ็กต์ BitmapDescriptor ที่ได้ไปยังเมธอด image() ของออบเจ็กต์ GroundOverlayOptions
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
  1. สร้าง float overlaySize สำหรับความกว้างเป็นเมตรของการวางซ้อนที่ต้องการ สำหรับตัวอย่างนี้ ความกว้าง 100f ทำงานได้ดี

ตั้งค่าพร็อพเพอร์ตี้ position สำหรับออบเจ็กต์ GroundOverlayOptions โดยเรียกใช้เมธอด position() และส่งพร็อพเพอร์ตี้ homeLatLng และ overlaySize

val overlaySize = 100f
val androidOverlay = GroundOverlayOptions()
   .image(BitmapDescriptorFactory.fromResource(R.drawable.android))
   .position(homeLatLng, overlaySize)
  1. เรียก addGroundOverlay() ในออบเจ็กต์ GoogleMap และส่งในออบเจ็กต์ GroundOverlayOptions
map.addGroundOverlay(androidOverlay)
  1. เรียกใช้แอป
  2. เปลี่ยนค่า zoomLevel เป็น 18f เพื่อดูรูปภาพ Android เป็นการวางซ้อน

b1b25b0acd6a9807.png

8. งาน: เปิดใช้การติดตามตำแหน่ง

ผู้ใช้มักจะใช้ Google Maps เพื่อดูตำแหน่งปัจจุบันของตน หากต้องการแสดงตำแหน่งอุปกรณ์บนแผนที่ คุณสามารถใช้ชั้นข้อมูลสถานที่ได้

ชั้นข้อมูลตำแหน่งจะเพิ่มไอคอนตำแหน่งของฉันลงในแผนที่

f317f84dcb3ac3a1.png

เมื่อผู้ใช้แตะปุ่ม แผนที่จะมีจุดศูนย์กลางอยู่ที่ตำแหน่งของอุปกรณ์ ตำแหน่งจะแสดงเป็นจุดสีน้ำเงินหากอุปกรณ์อยู่กับที่และเป็นรูปตัววีคว่ำสีน้ำเงินหากอุปกรณ์มีการเคลื่อนไหว

ในงานนี้ คุณจะได้เปิดใช้ชั้นข้อมูลตำแหน่ง

ขั้นตอน: ขอสิทธิ์เข้าถึงตำแหน่ง

การเปิดใช้การติดตามตำแหน่งใน Google Maps ต้องใช้โค้ดเพียงบรรทัดเดียว อย่างไรก็ตาม คุณต้องตรวจสอบว่าผู้ใช้ได้ให้สิทธิ์เข้าถึงตำแหน่ง (โดยใช้โมเดลสิทธิ์รันไทม์)

ในขั้นตอนนี้ คุณจะต้องขอสิทธิ์เข้าถึงตำแหน่งและเปิดใช้การติดตามตำแหน่ง

  1. ในไฟล์ AndroidManifest.xml ให้ยืนยันว่ามีสิทธิ์ FINE_LOCATION อยู่แล้ว Android Studio ได้แทรกสิทธิ์นี้ไว้เมื่อคุณเลือกเทมเพลต Google Maps
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. ใน MapsActivity ให้สร้างตัวแปรคลาส REQUEST_LOCATION_PERMISSION
private val REQUEST_LOCATION_PERMISSION = 1
  1. หากต้องการตรวจสอบว่ามีการให้สิทธิ์หรือไม่ ให้สร้างเมธอดใน MapsActivity ชื่อ isPermissionGranted() ในวิธีการนี้ ให้ตรวจสอบว่าผู้ใช้ให้สิทธิ์หรือไม่
private fun isPermissionGranted() : Boolean {
  return ContextCompat.checkSelfPermission(
       this,
      Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
  1. หากต้องการเปิดใช้การติดตามตำแหน่งในแอป ให้สร้างเมธอดใน MapsActivity ชื่อ enableMyLocation() โดยไม่ใช้อาร์กิวเมนต์และไม่แสดงผลใดๆ ด้านใน ให้ตรวจสอบสิทธิ์ ACCESS_FINE_LOCATION หากได้รับสิทธิ์ ให้เปิดใช้เลเยอร์ตำแหน่ง หรือไม่เช่นนั้น ให้ขอสิทธิ์
private fun enableMyLocation() {
   if (isPermissionGranted()) {
       map.isMyLocationEnabled = true 
   }
   else {
       ActivityCompat.requestPermissions(
           this,
           arrayOf<String>(Manifest.permission.ACCESS_FINE_LOCATION),
           REQUEST_LOCATION_PERMISSION
       )
   }
}
  1. เรียก enableMyLocation() จากการเรียกกลับของ onMapReady() เพื่อเปิดใช้เลเยอร์ตำแหน่ง
override fun onMapReady(googleMap: GoogleMap) {
   ...
   enableMyLocation()
}
  1. ลบล้างเมธอด onRequestPermissionsResult() ตรวจสอบว่า requestCode เท่ากับ REQUEST_LOCATION_PERMISSION หากมีสิทธิ์ แสดงว่าได้รับอนุญาตแล้ว หากได้รับสิทธิ์ ให้ตรวจสอบด้วยว่าอาร์เรย์ grantResults มี PackageManager.PERMISSION_GRANTED ในช่องแรกหรือไม่ หากเป็นกรณีนี้ โปรดโทรหา enableMyLocation()
override fun onRequestPermissionsResult(
   requestCode: Int,
   permissions: Array<String>,
   grantResults: IntArray) {
   if (requestCode == REQUEST_LOCATION_PERMISSION) {
       if (grantResults.contains(PackageManager.PERMISSION_GRANTED)) {
           enableMyLocation()
       }
   }
}
  1. เรียกใช้แอป จากนั้นจะมีกล่องโต้ตอบขอเข้าถึงตำแหน่งของอุปกรณ์ โปรดให้สิทธิ์

da7e23e00ec762c1.png

ตอนนี้แผนที่จะแสดงตำแหน่งปัจจุบันของอุปกรณ์โดยใช้จุดสีน้ำเงิน สังเกตว่ามีปุ่มตำแหน่ง หากคุณเลื่อนแผนที่ออกจากตำแหน่งของคุณและคลิกปุ่มนี้ แผนที่จะตั้งศูนย์กลางของแผนที่กลับไปที่ตำแหน่งของอุปกรณ์

5b12eda7f467bc2f.png

9. โค้ดโซลูชัน

ดาวน์โหลดโค้ดสำหรับ Codelab ที่เสร็จสมบูรณ์

$  git clone https://github.com/googlecodelabs/android-kotlin-geo-maps

หรือดาวน์โหลดที่เก็บเป็นไฟล์ ZIP, แตกไฟล์ และเปิดที่เก็บใน Android Studio ก็ได้

10. สรุป

ยินดีด้วย คุณเพิ่ม Google Maps ในแอป Kotlin และจัดรูปแบบแอปแล้ว

11. ดูข้อมูลเพิ่มเติม

เอกสารประกอบสำหรับนักพัฒนาซอฟต์แวร์ Android:

เอกสารอ้างอิง:

12. Codelab ถัดไป

สําหรับลิงก์ไปยัง Codelab อื่นๆ ในหลักสูตรนี้ โปรดดูหน้า Landing Page สำหรับ Android ขั้นสูงใน Kotlin