Android ขั้นสูงใน Kotlin 04.1: Android Google Maps

Codelab นี้เป็นส่วนหนึ่งของหลักสูตร Android ขั้นสูงใน Kotlin คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้ หากเรียนผ่าน Codelab ตามลําดับ แต่ไม่บังคับ Codelab ของหลักสูตรทั้งหมดจะแสดงอยู่ในหน้า Landing Page ขั้นสูงของ Android ใน Kotlin Codelab

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

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

สิ่งที่ต้องมีก่อน

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

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

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

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

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

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

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

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

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

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

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

google_maps_api.xml - คุณจะใช้ไฟล์การกําหนดค่านี้เพื่อเก็บคีย์ API เทมเพลตจะสร้างไฟล์ google_maps_api.xml 2 ไฟล์ คือ 1 ไฟล์สําหรับแก้ไขข้อบกพร่อง และอีก 1 ไฟล์สําหรับเผยแพร่ ไฟล์ของคีย์ 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.kt จะสร้าง SupportMapFragment ในเมธอด onCreate() และใช้คลาส&#39 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_key ที่มีข้อความ google_maps_api.xmlYOUR_KEY_HERE ในไฟล์ google_maps_api.xml
  10. เรียกใช้แอป คุณจะเห็นแผนที่ที่ฝังไว้ในกิจกรรมของคุณ พร้อมด้วยเครื่องหมายที่ตั้งไว้ในซิดนีย์ ออสเตรเลีย (เครื่องหมายซิดนีย์เป็นส่วนหนึ่งของเทมเพลตและคุณสามารถเปลี่ยนได้ในภายหลัง)

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

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

  1. ใน MapsActivity ให้คลิกขวาที่ mMap และคลิก Rector > เปลี่ยนชื่อ...

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

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

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

แผนที่ปกติ

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

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

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

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

ในงานนี้ คุณจะได้

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

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

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

  1. หากต้องการสร้างไฟล์ XML เมนูใหม่ ให้คลิกขวาที่ไดเรกทอรี res แล้วเลือก New> Android Resource File
  2. ตั้งชื่อไฟล์เป็น map_options ในกล่องโต้ตอบ
  3. เลือกเมนูสําหรับประเภททรัพยากร
  4. คลิกตกลง
  5. ในแท็บโค้ด ให้แทนที่โค้ดในไฟล์ใหม่ด้วยรหัสต่อไปนี้เพื่อสร้างตัวเลือกเมนูแผนที่ "none" ระบบยกเว้นประเภทแผนที่เนื่องจาก "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. คลิก เพื่อเปลี่ยนประเภทแผนที่ สังเกตว่ารูปแบบในแผนที่เปลี่ยนไประหว่างโหมดต่างๆ อย่างไร

โดยค่าเริ่มต้น โค้ดเรียกกลับ 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. เรียกใช้แอปของคุณ แผนที่ควรเลื่อนไปยังบ้านของคุณ ซูมไปที่ระดับที่ต้องการ และวางเครื่องหมายที่บ้าน

ขั้นที่ 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. แตะเครื่องหมายซึ่งจัดให้อยู่กึ่งกลางของหน้าจอ

ขั้นที่ 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. แตะเครื่องหมายเพื่อแสดงหน้าต่างข้อมูล

ขั้นตอนที่ 4: เพิ่ม POI 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. แตะจุดที่น่าสนใจเพื่อทําเครื่องหมาย แล้วแสดงชื่อของจุดที่น่าสนใจในหน้าต่างข้อมูล

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

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

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

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

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

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

  1. ในรายการประเภทฟีเจอร์ ให้เลือกถนน> เติมสี
  2. เปลี่ยนสีของถนนเป็นสีที่คุณเลือก (เช่น สีชมพู)

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

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

ขั้นตอนที่ 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. เพิ่มคําสั่ง "ถ้า" สําหรับ 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 และการจัดรูปแบบใหม่ควรแสดงให้เห็นด้วยธีมย้อนยุคและถนนของสีที่คุณเลือก

ขั้นที่ 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. เรียกใช้แอป เครื่องหมายที่ปรากฏหลังจากที่คลิกนานจะถูกแรเงาด้วยสีน้ําเงิน โปรดทราบว่าเครื่องหมาย POI ยังเป็นสีแดงเนื่องจากคุณไม่ได้เพิ่มการจัดรูปแบบให้กับเมธอด onPoiClick()

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

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

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

ในงานนี้ คุณจะได้เพิ่มการวางซ้อนพื้นรูปทรง Android ไปยังตําแหน่งบ้านของคุณ

  1. ดาวน์โหลดรูปภาพ Android นี้และบันทึกลงในโฟลเดอร์ res/drawable (ตรวจสอบว่าชื่อไฟล์คือ android.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 ในรูปแบบโฆษณาซ้อนทับ

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

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

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

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

การเปิดใช้การติดตามตําแหน่งใน 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. เรียกใช้แอป ควรมีกล่องโต้ตอบที่ขอสิทธิ์เข้าถึงตําแหน่งของอุปกรณ์ ดําเนินการต่อและอนุญาต

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

ดาวน์โหลดโค้ดสําหรับ Codelab ที่เสร็จสิ้นแล้ว

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


คุณอาจดาวน์โหลดที่เก็บเป็นไฟล์ ZIP แล้วแตกไฟล์ และเปิดใน Android Studio ได้ด้วย

ดาวน์โหลด ZIP

  • หากต้องการใช้ Maps API คุณต้องมีคีย์ API จากคอนโซล Google API
  • ใน Android Studio การใช้เทมเพลตกิจกรรมของ Google Maps จะสร้าง Activity ที่มี SupportMapFragment เพียงรายการเดียวในรูปแบบของแอป เทมเพลตยังเพิ่ม ACCESS_FINE_PERMISSION ลงในไฟล์ Manifest ของแอปและใช้ OnMapReadyCallback ในกิจกรรมด้วย และจะลบล้างเมธอด onMapReady() ที่จําเป็น

หากต้องการเปลี่ยนประเภทแผนที่ของ GoogleMap ขณะรันไทม์ ให้ใช้เมธอด GoogleMap.setMapType() Google Maps อาจเป็นประเภทแผนที่อย่างใดอย่างหนึ่งต่อไปนี้

  • ปกติ: แผนถนนทั่วไป แสดงถนน สถานที่บางแห่งสร้างโดยมนุษย์ และฟีเจอร์ทางธรรมชาติที่สําคัญ เช่น แม่น้ํา รวมถึงป้ายกํากับของถนนและฟีเจอร์
  • ไฮบริด: ข้อมูลดาวเทียมถ่ายภาพที่เพิ่มแผนที่ถนน รวมถึงป้ายกํากับของถนนและฟีเจอร์
  • ดาวเทียม: ข้อมูลภาพถ่าย ไม่แสดงป้ายกํากับถนนและฟีเจอร์
  • ภูมิประเทศ: ข้อมูลภูมิประเทศ แผนที่ประกอบด้วยสี เส้นชั้นความสูงและป้ายกํากับ และการแรเงามุมมอง นอกจากนี้ยังแสดงถนนและป้ายกํากับบางรายการด้วย
  • ไม่มี: ไม่มีชิ้นส่วนแผนที่พื้นฐาน

เกี่ยวกับ Google Maps

  • เครื่องหมายเป็นตัวบ่งชี้สถานที่ตั้งทางภูมิศาสตร์ที่เจาะจง
  • เมื่อแตะ ลักษณะการทํางานเริ่มต้นของเครื่องหมายจะเป็นการแสดงหน้าต่างข้อมูลพร้อมข้อมูลเกี่ยวกับตําแหน่ง
  • โดยค่าเริ่มต้น จุดสนใจ (POI) จะปรากฏในแผนที่ฐานพร้อมด้วยไอคอนที่เกี่ยวข้อง จุดที่น่าสนใจ ได้แก่ สวนสาธารณะ โรงเรียน อาคารรัฐบาล และอื่นๆ
  • นอกจากนี้ จุดที่น่าสนใจสําหรับธุรกิจ (ร้านค้า ร้านอาหาร โรงแรม และอื่นๆ) จะปรากฏโดยค่าเริ่มต้นบนแผนที่เมื่อประเภทแผนที่คือ normal
  • คุณบันทึกจุดที่น่าสนใจได้โดยใช้ OnPoiClickListener
  • คุณสามารถเปลี่ยนลักษณะที่ปรากฏขององค์ประกอบเกือบทุกอย่างของ Google Maps ได้โดยใช้วิซาร์ดการจัดรูปแบบ วิซาร์ดการสร้างรูปแบบจะสร้างไฟล์ JSON ที่คุณส่งเข้าไปใน Google Maps โดยใช้เมธอด setMapStyle()
  • คุณสามารถปรับแต่งเครื่องหมายได้โดยเปลี่ยนสีเริ่มต้น หรือแทนที่ไอคอนเครื่องหมายเริ่มต้นด้วยรูปภาพที่กําหนดเอง

ข้อมูลอื่นๆ ที่สำคัญมีดังนี้

  • ใช้การวางซ้อนพื้นเพื่อแก้ไขรูปภาพตามสถานที่ตั้งทางภูมิศาสตร์
  • ใช้ออบเจ็กต์ GroundOverlayOptions เพื่อระบุรูปภาพ ขนาดรูปภาพเป็นหน่วยเมตร และตําแหน่งรูปภาพ ส่งออบเจ็กต์นี้ไปยังเมธอด GoogleMap.addGroundOverlay() เพื่อตั้งค่าการวางซ้อนให้แผนที่
  • ถ้าแอปของคุณมีสิทธิ์ ACCESS_FINE_LOCATION คุณสามารถเปิดใช้การติดตามตําแหน่งได้โดยตั้งค่า map.isMyLocationEnabled = true
  • โค้ดนี้ไม่ครอบคลุมอยู่ใน Codelab นี้ แต่คุณสามารถให้ข้อมูลเพิ่มเติมเกี่ยวกับตําแหน่งโดยใช้ Google Street View ซึ่งเป็นรูปภาพพาโนรามาที่ไปยังส่วนต่างๆ ของตําแหน่งนั้นๆ ได้

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

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

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