เพิ่มแผนที่ 3 มิติลงในแอป

เลือกแพลตฟอร์ม: Android iOS JavaScript

แผนที่ 3 มิติที่แสดงนิวยอร์กซิตี้

หน้านี้จะอธิบายตัวอย่างวิธีเพิ่มแผนที่ 3 มิติพื้นฐานลงใน แอป Android โดยใช้ Maps 3D SDK สำหรับ Android วิธีการในหน้านี้ ถือว่าคุณได้ทำตามขั้นตอนในหน้าการตั้งค่า เสร็จเรียบร้อยแล้ว และมีข้อมูลต่อไปนี้

  • โปรเจ็กต์ Google Cloud ที่เปิดใช้ Maps 3D SDK สำหรับ Android
  • คีย์ API ที่กำหนดค่าให้ใช้กับ Maps 3D SDK สำหรับ Android
  • โปรเจ็กต์ Android Studio ที่ตั้งค่าให้ใช้กับ Maps 3D SDK สำหรับ Android

ดูข้อมูลเพิ่มเติมเกี่ยวกับข้อกำหนดเบื้องต้นเหล่านี้ได้ที่ การตั้งค่า

ส่วนที่ 1: อัปเดตไฟล์เลย์เอาต์ (activity_main.xml) เพื่อเพิ่มคอมโพเนนต์ Map3DView

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

  1. เปิดไฟล์เลย์เอาต์ของกิจกรรมหลัก ซึ่งโดยปกติจะอยู่ที่ app/src/main/res/layout/activity_main.xml

  2. ในรูท ConstraintLayout (หรือองค์ประกอบเลย์เอาต์รูท) ให้เพิ่มเนมสเปซ map3d XML ดังนี้

    xmlns:map3d="http://schemas.android.com/apk/res-auto"
    
  3. ลบ <TextView> เริ่มต้นที่แสดงข้อความ "Hello World!"

  4. เพิ่มคอมโพเนนต์ Map3DView ลงในเลย์เอาต์ คุณปรับแต่งตำแหน่งกล้อง และแอตทริบิวต์อื่นๆ ได้ดังนี้

    <?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:map3d="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
      android:id="@+id/main"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".MainActivity">
    
      <com.google.android.gms.maps3d.Map3DView
        android:id="@+id/map3dView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        map3d:mode="hybrid"
        map3d:centerLat="38.544012"
        map3d:centerLng="-107.670428"
        map3d:centerAlt="2427.6"
        map3d:heading="310"
        map3d:tilt="63"
        map3d:range="8266"
        map3d:roll="0"
        map3d:minAltitude="0"
        map3d:maxAltitude="1000000"
        map3d:minHeading="0"
        map3d:maxHeading="360"
        map3d:minTilt="0"
        map3d:maxTilt="90"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

ส่วนที่ 2: อัปเดต MainActivity.kt

ขั้นตอนต่อไปนี้จะเริ่มต้นคอมโพเนนต์ Map3DView ที่เพิ่มลงในไฟล์ activity_main.xml ในส่วนที่ 1 และจัดการเหตุการณ์วงจรของคอมโพเนนต์

โปรดทราบว่า Maps 3D SDK สำหรับ Android รองรับอินสแตนซ์ที่ใช้งานอยู่Map3DView เพียงครั้งละ 1 รายการเท่านั้น การแสดงMap3DViewอินสแตนซ์หลายรายการพร้อมกัน (เช่น ในเลย์เอาต์เดียวกันหรือกิจกรรมหรือ Fragment ที่มองเห็นได้แตกต่างกัน) ไม่ รองรับและอาจทำให้เกิดปัญหาในการแสดงผล เช่น หน้าจอสีดำในมุมมองรอง

นอกจากนี้ Map3DView ทั้งหมดจะแชร์และแสดงสถานะแผนที่เดียวกัน (เช่น ตำแหน่งกล้อง เครื่องหมายที่เพิ่ม รูปหลายเหลี่ยม ฯลฯ) ซึ่งจะยังคงอยู่แม้ว่า Map3DView หนึ่งจะถูกทำลาย (ใช้ onDestroy) และมีการสร้างอีกอันขึ้นมา เว้นแต่จะล้างด้วยตนเอง เช่น หากคุณเพิ่มเครื่องหมายใน Map3DView1 แล้วทำลาย และสร้าง Map3DView2 เครื่องหมายเดียวกันนั้นจะยังคงอยู่ใน Map3DView2

ความรับผิดชอบของนักพัฒนาแอป:

  • ดูครั้งละ 1 รายการ: ตรวจสอบว่ามี Map3DView เพียงรายการเดียวในส่วนที่ใช้งานอยู่ของ ลำดับชั้นการดูในทุกขณะ
  • การล้างข้อมูลด้วยตนเอง: เมื่อเปลี่ยนจาก Map3DView หนึ่ง (เช่น Map3DView1) ไปยังอีกหนึ่ง (เช่น Map3DView2) คุณต้องเรียกใช้ onDestroy() ในอินสแตนซ์เก่า (Map3DView1) เนื่องจากมีการแชร์สถานะแผนที่พื้นฐาน เพื่อให้แน่ใจว่า Map3DView2 จะเริ่มต้นด้วยสถานะใหม่หรือสถานะที่เฉพาะเจาะจง คุณจึงมีหน้าที่รับผิดชอบในการล้างสถานะที่ Map3DView1 ตั้งค่าไว้ด้วยตนเอง ซึ่งรวมถึงการนำเครื่องหมาย ภาพซ้อน ฯลฯ ออก และการรีเซ็ตตำแหน่งกล้องโดยใช้GoogleMap3Dออบเจ็กต์ ที่ได้รับใน OnMap3DViewReadyCallback
  1. เปิดไฟล์ MainActivity.kt ซึ่งโดยปกติจะอยู่ที่ app/src/main/java/com/example/yourpackagename/MainActivity.kt

  2. เพิ่มการนำเข้าที่จำเป็นสำหรับ Maps 3D SDK สำหรับ Android ดังนี้

    import com.google.android.gms.maps3d.GoogleMap3D
    import com.google.android.gms.maps3d.Map3DView
    import com.google.android.gms.maps3d.OnMap3DViewReadyCallback
    
  3. แก้ไขMainActivity คลาสเพื่อใช้ OnMap3DViewReadyCallback ดังนี้

    class MainActivity : AppCompatActivity(), OnMap3DViewReadyCallback {
    
  4. ประกาศตัวแปรสำหรับ Map3DView และ GoogleMap3D ดังนี้

    private lateinit var map3DView: Map3DView
    private var googleMap3D: GoogleMap3D? = null
    
  5. ในเมธอด onCreate หลังจาก setContentView(...) และบล็อก ViewCompat.setOnApplyWindowInsetsListener ให้เริ่มต้น map3DView เรียกใช้เมธอดวงจรของ onCreate และขอแผนที่ แบบไม่พร้อมกัน

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
    
        map3DView = findViewById(R.id.map3dView)
        map3DView.onCreate(savedInstanceState)
        map3DView.getMap3DViewAsync(this)
    }
    
  6. แทนที่เมธอด onMap3DViewReady ระบบจะทริกเกอร์การเรียกกลับนี้เมื่อแผนที่พร้อมใช้งาน

    override fun onMap3DViewReady(googleMap3D: GoogleMap3D) {
        // Interact with the googleMap3D object here
        this.googleMap3D = googleMap3D
        // You can now make calls to the googleMap3D object, e.g.,
        // googleMap3D.cameraController.flyTo(camera { ... })
    }
    
  7. ส่งต่อเหตุการณ์วงจรของกิจกรรมจากกิจกรรมไปยัง Map3DView โดยเพิ่มการลบล้างต่อไปนี้ลงใน MainActivity

    override fun onStart() {
        super.onStart()
        map3DView.onStart()
    }
    
    override fun onResume() {
        super.onResume()
        map3DView.onResume()
    }
    
    override fun onPause() {
        map3DView.onPause()
        super.onPause()
    }
    
    override fun onStop() {
        map3DView.onStop()
        super.onStop()
    }
    
    override fun onDestroy() {
        map3DView.onDestroy()
        super.onDestroy()
    }
    
    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        map3DView.onSaveInstanceState(outState)
    }
    
    override fun onLowMemory() {
        super.onLowMemory()
        map3DView.onLowMemory()
    }
    

ส่วนที่ 3: ซิงค์ Gradle และเรียกใช้

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

  1. หากต้องการซิงค์โปรเจ็กต์กับ Gradle ให้เลือก ไฟล์ > ซิงค์โปรเจ็กต์กับไฟล์ Gradle

  2. หากต้องการสร้างและเรียกใช้แอปในโปรแกรมจำลองหรืออุปกรณ์จริง ให้เลือก เรียกใช้ > เรียกใช้

หากกำหนดค่าทุกอย่างถูกต้อง คุณควรเห็นแผนที่ 3 มิติแสดงในแอป โดยมีจุดศูนย์กลางอยู่ใกล้กับพิกัดที่ระบุใน activity_main.xml

ขั้นตอนถัดไป

ตอนนี้คุณได้เพิ่มแผนที่ 3 มิติพื้นฐานลงในแอปแล้ว คุณสามารถสำรวจฟีเจอร์ขั้นสูงเพิ่มเติมของ Maps 3D SDK สำหรับ Android เช่น ภาพเคลื่อนไหวเส้นทางกล้อง เครื่องหมาย 3 มิติ หรือ รูปหลายเหลี่ยม

ฟังกิจกรรมการคลิกแผนที่

หากต้องการฟังเหตุการณ์การคลิกบนแผนที่ ให้ใช้ GoogleMap3D.setMap3DClickListener ระบบจะเรียกใช้ Listener นี้เมื่อผู้ใช้ คลิกบนแผนที่ และจะระบุตำแหน่งและรหัสสถานที่ของจุดที่คลิก

ตัวอย่างต่อไปนี้แสดงวิธีตั้งค่าเครื่องมือฟังการคลิกแผนที่

googleMap3D.setMap3DClickListener { location, placeId ->
    lifecycleScope.launch(Dispatchers.Main) {
        if (placeId != null) {
            Toast.makeText(this@MainActivity, "Clicked on place with ID: $placeId", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(this@MainActivity, "Clicked on location: $location", Toast.LENGTH_SHORT).show()
        }
    }
}

โปรดทราบว่าตัวแฮนเดิลการคลิกจะไม่ทํางานในเธรดหลัก (หรือ UI) หากต้องการทำการเปลี่ยนแปลง UI (เช่น แสดงข้อความ Toast) คุณต้องเปลี่ยนไปใช้เทรดหลัก สำหรับ Kotlin คุณทำได้โดยใช้ lifecycleScope.launch(Dispatchers.Main)