1. ก่อนเริ่มต้น
โค้ดแล็บนี้จะสอนวิธีสร้างแอปแผนที่ 3 มิติใน SwiftUI โดยใช้ Maps 3D SDK สำหรับ iOS
คุณจะได้เรียนรู้:
- วิธีควบคุมกล้องเพื่อดูสถานที่และบินไปรอบๆ แผนที่
- วิธีเพิ่มเครื่องหมายและโมเดล
- วิธีวาดเส้นและรูปหลายเหลี่ยม
- วิธีจัดการกับการคลิกของเครื่องหมายสถานที่โดยผู้ใช้
ข้อกำหนดเบื้องต้น
- โปรเจ็กต์ Google Console ที่เปิดใช้การเรียกเก็บเงิน
- คีย์ API ซึ่งอาจจํากัดไว้สําหรับ Maps 3D SDK สําหรับ iOS
- ความรู้พื้นฐานเกี่ยวกับการพัฒนา iOS ด้วย SwiftUI
สิ่งที่ต้องทำ
- ตั้งค่า Xcode และนํา SDK มาใช้โดยใช้ Swift Package Manager
- กำหนดค่าแอปให้ใช้คีย์ API
- เพิ่มแผนที่ 3 มิติพื้นฐานลงในแอป
- ควบคุมกล้องให้บินไปยังและรอบๆ สถานที่ที่ต้องการ
- เพิ่มเครื่องหมาย เส้น รูปหลายเหลี่ยม และโมเดลลงในแผนที่
สิ่งที่คุณต้องมี
- Xcode 15 ขึ้นไป
2. ตั้งค่า
ในขั้นตอนการเปิดใช้ต่อไปนี้ คุณจะต้องเปิดใช้ Maps 3D SDK สำหรับ iOS
ตั้งค่า Google Maps Platform
หากยังไม่มีบัญชี Google Cloud Platform และโปรเจ็กต์ที่เปิดใช้การเรียกเก็บเงิน โปรดดูคู่มือเริ่มต้นใช้งาน Google Maps Platform เพื่อสร้างบัญชีการเรียกเก็บเงินและโปรเจ็กต์
- ใน Cloud Console ให้คลิกเมนูแบบเลื่อนลงของโปรเจ็กต์ แล้วเลือกโปรเจ็กต์ที่ต้องการใช้สำหรับโค้ดแล็บนี้
- เปิดใช้ Google Maps Platform API และ SDK ที่จําเป็นสําหรับโค้ดแล็บนี้ใน Google Cloud Marketplace โดยทำตามขั้นตอนในวิดีโอนี้หรือเอกสารประกอบนี้
- สร้างคีย์ API ในหน้าข้อมูลเข้าสู่ระบบของ Cloud Console คุณสามารถทำตามขั้นตอนในวิดีโอนี้หรือเอกสารประกอบนี้ คำขอทั้งหมดที่ส่งไปยัง Google Maps Platform ต้องใช้คีย์ API
เปิดใช้ Maps 3D SDK สำหรับ iOS
คุณดู Maps 3D SDK สําหรับ iOS ได้โดยใช้ลิงก์เมนู Google Maps Platform > API และบริการในคอนโซล
คลิก "เปิดใช้" เพื่อเปิดใช้ API ในโปรเจ็กต์ที่เลือก
3. สร้างแอป SwiftUI พื้นฐาน
หมายเหตุ: คุณดูโค้ดโซลูชันของแต่ละขั้นตอนได้ในที่เก็บแอปตัวอย่างของ Codelab ใน GitHub
สร้างแอปใหม่ใน Xcode
โค้ดสําหรับขั้นตอนนี้จะอยู่ในโฟลเดอร์ GoogleMaps3DDemo ใน GitHub
เปิด Xcode และสร้างแอปใหม่ ระบุ SwiftUI
ตั้งชื่อแอปว่า GoogleMaps3DDemo
ที่มีชื่อแพ็กเกจ com.example.GoogleMaps3DDemo
นําเข้าไลบรารี GoogleMaps3D ไปยังโปรเจ็กต์
เพิ่ม SDK ลงในโปรเจ็กต์โดยใช้ Swift Package Manager
ในโปรเจ็กต์หรือเวิร์กスペース Xcode ให้ไปที่ File > Add Package Dependencies ป้อน https://github.com/googlemaps/ios-maps-3d-sdk เป็น URL, กด Enter เพื่อดึงข้อมูลแพ็กเกจ แล้วคลิก "เพิ่มแพ็กเกจ"
จากหน้าต่าง "เลือกผลิตภัณฑ์แพ็กเกจ" ให้ยืนยันว่าระบบจะเพิ่ม GoogleMaps3D
ไปยังเป้าหมายหลักที่คุณกำหนด เมื่อดำเนินการเสร็จแล้ว ให้คลิก "เพิ่มแพ็กเกจ"
หากต้องการยืนยันการติดตั้ง ให้ไปที่แผงทั่วไปของเป้าหมาย คุณควรเห็นแพ็กเกจที่ติดตั้งแล้วในเฟรมเวิร์ก ไลบรารี และเนื้อหาที่ฝัง นอกจากนี้ คุณยังดูส่วน "แพ็กเกจที่ต้องพึ่งพา" ของ Project Navigator เพื่อยืนยันแพ็กเกจและเวอร์ชันของแพ็กเกจได้ด้วย
เพิ่มคีย์ API
คุณสามารถฝังคีย์ API ไว้ในโค้ดของแอปได้ แต่วิธีนี้ไม่ใช่แนวทางปฏิบัติแนะนำ การเพิ่มไฟล์การกําหนดค่าช่วยให้คุณเก็บคีย์ API ไว้เป็นความลับและหลีกเลี่ยงการตรวจสอบคีย์ดังกล่าวในระบบควบคุมแหล่งที่มา
สร้างไฟล์การกําหนดค่าใหม่ในโฟลเดอร์รูทของโปรเจ็กต์
ใน Xcode ให้ตรวจสอบว่าคุณกำลังดูหน้าต่างเครื่องมือสำรวจโปรเจ็กต์ คลิกขวาที่รูทของโปรเจ็กต์แล้วเลือก "ไฟล์ใหม่จากเทมเพลต" เลื่อนจนกว่าจะเห็น "ไฟล์การตั้งค่าการกําหนดค่า" เลือกตัวเลือกนี้ แล้วคลิก "ถัดไป" ตั้งชื่อไฟล์เป็น Config.xcconfig
และตรวจสอบว่าได้เลือกโฟลเดอร์รูทของโปรเจ็กต์แล้ว คลิก "สร้าง" เพื่อสร้างไฟล์
ในเครื่องมือแก้ไข ให้เพิ่มบรรทัดลงในไฟล์การกําหนดค่า ดังนี้ MAPS_API_KEY = YOUR_API_KEY
แทนที่ YOUR_API_KEY
ด้วยคีย์ API ของคุณ
เพิ่มการตั้งค่านี้ลงใน Info.plist
โดยเลือกรูทโปรเจ็กต์แล้วคลิกแท็บ "ข้อมูล"
เพิ่มพร็อพเพอร์ตี้ใหม่ชื่อ MAPS_API_KEY
ที่มีค่าเป็น $(MAPS_API_KEY)
โค้ดตัวอย่างแอปมีไฟล์ Info.plist
ที่ระบุพร็อพเพอร์ตี้นี้
เพิ่มแผนที่
เปิดไฟล์ชื่อ GoogleMaps3DDemoApp.swift
นี่เป็นจุดเข้าและการนำทางหลักของแอป
ซึ่งจะเรียก ContentView()
ซึ่งแสดงข้อความ Hello World
เปิด ContentView.swift
ในเครื่องมือแก้ไข
เพิ่มคำสั่ง import
สำหรับ GoogleMaps3D
ลบโค้ดภายในโค้ดบล็อก var body: some View {}
ประกาศ Map()
ใหม่ภายใน body
การกําหนดค่าขั้นต่ำที่คุณต้องใช้ในการเริ่มต้น Map
คือ MapMode
ค่านี้มีค่าที่เป็นไปได้ 2 ค่า ได้แก่
.hybrid
- ภาพถ่ายจากดาวเทียมที่มีถนนและป้ายกำกับ หรือ.satellite
- ภาพถ่ายจากดาวเทียมเท่านั้น
เลือก .hybrid
เลย
ไฟล์ ContentView.swift
ควรมีลักษณะดังนี้
import GoogleMaps3D
import SwiftUI
@main
struct ContentView: View {
var body: some View {
Map(mode: .hybrid)
}
}
ตั้งค่าคีย์ API
คุณต้องตั้งค่าคีย์ API ก่อนแผนที่จะเริ่มต้น
ซึ่งทำได้โดยการตั้งค่า Map.apiKey
ในตัวแฮนเดิลเหตุการณ์ init()
ของ View
ที่มีแผนที่ นอกจากนี้ คุณยังตั้งค่าใน GoogleMaps3DDemoApp.swift
ก่อนที่จะโทรหา ContentView()
ได้ด้วย
ใน GoogleMaps3DDemoApp.swift
ให้ตั้งค่า Map.apiKey
ในเครื่องจัดการเหตุการณ์ onAppear
ของ WindowGroup
ดึงข้อมูลคีย์ API จากไฟล์การกําหนดค่า
ใช้ Bundle.main.infoDictionary
เพื่อเข้าถึงการตั้งค่า MAPS_API_KEY
ที่คุณสร้างไว้ในไฟล์การกําหนดค่า
import GoogleMaps3D
import SwiftUI
@main
struct GoogleMaps3DDemoApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.onAppear {
guard let infoDictionary: [String: Any] = Bundle.main.infoDictionary else {
fatalError("Info.plist not found")
}
guard let apiKey: String = infoDictionary["MAPS_API_KEY"] as? String else {
fatalError("MAPS_API_KEY not set in Info.plist")
}
Map.apiKey = apiKey
}
}
}
สร้างและเรียกใช้แอปเพื่อตรวจสอบว่าโหลดได้อย่างถูกต้อง คุณจะเห็นแผนที่โลก
4. ใช้กล้องเพื่อควบคุมมุมมองแผนที่
สร้างออบเจ็กต์สถานะกล้อง
มุมมองแผนที่ 3 มิติจะควบคุมโดยคลาส Camera
ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีระบุตำแหน่ง ระดับความสูง ทิศทาง การเอียง การพลิก และระยะเพื่อปรับแต่งมุมมองแผนที่
สร้างคลาส Helpers เพื่อจัดเก็บการตั้งค่ากล้อง
เพิ่มไฟล์ว่างใหม่ชื่อ MapHelpers.swift
ในไฟล์ใหม่ ให้นำเข้า GoogleMaps3D
และเพิ่มส่วนขยายลงในคลาส Camera
เพิ่มตัวแปรชื่อ sanFrancisco
เริ่มต้นตัวแปรนี้เป็นออบเจ็กต์ Camera
ใหม่ วางกล้องที่ latitude: 37.39, longitude: -122.08
import GoogleMaps3D
extension Camera {
public static var sanFrancisco: Camera = .init(latitude: 37.39, longitude: -122.08)
}
เพิ่มมุมมองใหม่ลงในแอป
สร้างไฟล์ใหม่ชื่อ CameraDemo.swift
เพิ่มเค้าโครงพื้นฐานของมุมมอง SwiftUI ใหม่ลงในไฟล์
เพิ่มตัวแปร @State
ชื่อ camera
ประเภท Camera
เริ่มต้นใช้งานกับกล้อง sanFrancisco
ที่คุณเพิ่งกำหนด
การใช้ @State
ช่วยให้คุณเชื่อมโยงแผนที่กับสถานะของกล้องและใช้แผนที่เป็นแหล่งข้อมูลที่ถูกต้องได้
@State var camera: Camera = .sanFrancisco
เปลี่ยนการเรียกใช้ฟังก์ชัน Map()
ให้รวมพร็อพเพอร์ตี้ camera
ใช้การเชื่อมโยงสถานะกล้อง $camera
เพื่อเริ่มต้นค่าของพร็อพเพอร์ตี้ camera
ให้กับออบเจ็กต์ @State
ของกล้อง (.sanFrancisco
)
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
เพิ่ม UI การนําทางพื้นฐานลงในแอป
เพิ่ม NavigationView
ไปยังจุดแรกเข้าของแอปหลัก GoogleMaps3DDemoApp.swift
ซึ่งจะช่วยให้ผู้ใช้เห็นรายการเดโมและคลิกแต่ละรายการเพื่อเปิดได้
แก้ไข GoogleMaps3DDemoApp.swift
เพื่อเพิ่ม NavigationView
ใหม่
เพิ่ม List
ที่มีประกาศ NavigationLink
2 รายการ
NavigationLink
รายการแรกควรเปิด ContentView()
พร้อมText
คำอธิบาย Basic Map
NavigationLink
ตัวที่ 2 ควรเปิด CameraDemo()
...
NavigationView {
List {
NavigationLink(destination: ContentView()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
}
}
...
เพิ่มตัวอย่าง Xcode
การแสดงตัวอย่างเป็นฟีเจอร์ที่มีประสิทธิภาพของ Xcode ที่ช่วยให้คุณดูและโต้ตอบกับแอปขณะทำการเปลี่ยนแปลงได้
หากต้องการเพิ่มตัวอย่างเพลง ให้เปิด CameraDemo.swift
เพิ่มโค้ดบล็อก #Preview {}
ไว้นอก struct
#Preview {
CameraDemo()
}
เปิดหรือรีเฟรชบานหน้าต่างแสดงตัวอย่างใน Xcode แผนที่ควรแสดงซานฟรานซิสโก
ตั้งค่ามุมมอง 3 มิติที่กำหนดเอง
คุณสามารถระบุพารามิเตอร์เพิ่มเติมเพื่อควบคุมกล้องได้ ดังนี้
heading
: ทิศทางเป็นองศาจากเหนือเพื่อเล็งกล้องtilt
: มุมเอียงเป็นองศา โดย 0 หมายถึงเหนือศีรษะโดยตรง และ 90 หมายถึงมองในแนวนอนroll
: มุมของการหมุนรอบระนาบแนวตั้งของกล้องเป็นองศาrange
: ระยะทางของกล้องเป็นเมตรจากตำแหน่งละติจูด ลองจิจูดaltitude
: ความสูงของกล้องเหนือระดับน้ำทะเล
หากคุณไม่ได้ระบุพารามิเตอร์เพิ่มเติมเหล่านี้ ระบบจะใช้ค่าเริ่มต้น
หากต้องการให้มุมมองกล้องแสดงข้อมูล 3 มิติมากขึ้น ให้ตั้งค่าพารามิเตอร์เริ่มต้นให้แสดงมุมมองที่เอียงและใกล้ขึ้น
แก้ไข Camera
ที่คุณกำหนดไว้ใน MapHelpers.swift
ให้รวมค่าสำหรับ altitude
, heading
, tilt
, roll
และ range
public static var sanFrancisco: Camera = .init(
latitude: 37.7845812,
longitude: -122.3660241,
altitude: 585,
heading: 288.0,
tilt: 75.0,
roll: 0.0,
range: 100)
สร้างและเรียกใช้แอปเพื่อดูและสำรวจมุมมอง 3 มิติแบบใหม่
5. ภาพเคลื่อนไหวพื้นฐานของกล้อง
จนถึงตอนนี้คุณได้ใช้กล้องเพื่อระบุตำแหน่งเดียวด้วยการเอียง ระดับความสูง ทิศทาง และระยะ ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีย้ายมุมมองกล้องด้วยการทำภาพเคลื่อนไหวของพร็อพเพอร์ตี้เหล่านี้จากสถานะเริ่มต้นไปยังสถานะใหม่
บินไปยังสถานที่
คุณจะใช้เมธอด Map.flyCameraTo()
เพื่อแสดงภาพเคลื่อนไหวของกล้องจากตำแหน่งเริ่มต้นไปยังตำแหน่งใหม่
เมธอด flyCameraTo()
มีพารามิเตอร์หลายรายการ ดังนี้
Camera
ที่แสดงตำแหน่งสิ้นสุดduration
: ระยะเวลาที่ภาพเคลื่อนไหวจะแสดง หน่วยเป็นวินาทีtrigger
: ออบเจ็กต์ที่สังเกตได้ซึ่งจะทริกเกอร์ภาพเคลื่อนไหวเมื่อสถานะเปลี่ยนแปลงcompletion
: โค้ดที่จะดำเนินการเมื่อภาพเคลื่อนไหวเสร็จสมบูรณ์
กําหนดสถานที่ที่จะบินไป
เปิดไฟล์ MapHelpers.swift
กำหนดออบเจ็กต์กล้องใหม่เพื่อแสดงซีแอตเทิล
public static var seattle: Camera = .init(latitude:
47.6210296,longitude: -122.3496903, heading: 149.0, tilt: 77.0, roll: 0.0, range: 4000)
เพิ่มปุ่มเพื่อเรียกให้ภาพเคลื่อนไหวทำงาน
เปิด CameraDemo.swift
ประกาศตัวแปรบูลีนใหม่ภายใน struct
ตั้งชื่อว่า animate
โดยมีค่าเริ่มต้นเป็น false
@State private var animate: Bool = false
เพิ่ม Button
ไว้ใต้ VStack
Button
จะเริ่มภาพเคลื่อนไหวของแผนที่
ตั้งชื่อ Button
ให้เหมาะสม เช่น "เริ่มบิน"Text
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera:Camera = .sanFrancisco
@State private var animate: Bool = false
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
Button("Start Flying") {
}
}
}
}
ใน Button Closure ให้เพิ่มโค้ดเพื่อสลับสถานะของตัวแปร animate
Button("Start Flying") {
animate.toggle()
}
เริ่มภาพเคลื่อนไหว
เพิ่มโค้ดเพื่อเรียกใช้ภาพเคลื่อนไหว flyCameraTo()
เมื่อสถานะของตัวแปร animate
เปลี่ยนแปลง
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
.flyCameraTo(
.seattle,
duration: 5,
trigger: animate,
completion: { }
)
Button("Start Flying") {
animate.toggle()
}
}
}
บินรอบสถานที่
คุณสามารถบินรอบสถานที่โดยใช้วิธีการ Map.flyCameraAround()
โดยเมธอดนี้ใช้พารามิเตอร์หลายรายการ ดังนี้
Camera
ที่กําหนดตําแหน่งและมุมมองduration
วินาทีrounds
: จำนวนครั้งที่แสดงภาพเคลื่อนไหวซ้ำtrigger
: ออบเจ็กต์ที่สังเกตได้ซึ่งจะทริกเกอร์ภาพเคลื่อนไหวcallback
: โค้ดที่จะทำงานเมื่อภาพเคลื่อนไหวทำงาน
กําหนดตัวแปร @State
ใหม่ชื่อ flyAround
ที่มีค่าเริ่มต้นเป็น false
เมื่อดำเนินการเสร็จแล้ว ให้เพิ่มการเรียกใช้ flyCameraAround()
หลังการเรียกใช้เมธอด flyCameraTo()
ทันที
ระยะเวลาของภาพพารามิเตอร์ควรค่อนข้างนานเพื่อให้มุมมองเปลี่ยนอย่างราบรื่น
อย่าลืมเรียกใช้ภาพเคลื่อนไหว flyCameraAround()
โดยการเปลี่ยนสถานะของออบเจ็กต์ทริกเกอร์เมื่อ flyCameraTo()
เสร็จสมบูรณ์
โค้ดของคุณควรมีลักษณะดังนี้
import SwiftUI
import GoogleMaps3D
struct CameraDemo: View {
@State var camera:Camera = .sanFrancisco
@State private var animate: Bool = false
@State private var flyAround: Bool = false
var body: some View {
VStack{
Map(camera: $camera, mode: .hybrid)
.flyCameraTo(
.seattle,
duration: 5,
trigger: animate,
completion: { flyAround = true }
)
.flyCameraAround(
.seattle,
duration: 15,
rounds: 0.5,
trigger: flyAround,
callback: { }
)
Button("Start Flying") {
animate.toggle()
}
}
}
}
#Preview {
CameraDemo()
}
แสดงตัวอย่างหรือเรียกใช้แอปเพื่อดูว่ากล้องโฟกัสไปยังจุดหมายต่างๆ เมื่อภาพเคลื่อนไหว flyCameraTo()
แสดงเสร็จแล้ว
6. เพิ่มเครื่องหมายลงในแผนที่
ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีวาดหมุดบนแผนที่
คุณจะต้องสร้างออบเจ็กต์ Marker
และเพิ่มลงในแผนที่ SDK จะใช้ไอคอนเริ่มต้นสำหรับเครื่องหมาย สุดท้าย คุณจะต้องปรับความสูงของตัวทำเครื่องหมายและพร็อพเพอร์ตี้อื่นๆ เพื่อเปลี่ยนลักษณะการแสดงผล
สร้างมุมมอง SwiftUI ใหม่สําหรับการสาธิตเครื่องหมาย
เพิ่มไฟล์ Swift ใหม่ลงในโปรเจ็กต์ ตั้งชื่อว่า MarkerDemo.swift
เพิ่มโครงร่างของมุมมอง SwiftUI และเริ่มต้นแผนที่เช่นเดียวกับใน CameraDemo
import SwiftUI
import GoogleMaps3D
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
}
}
}
เริ่มต้นออบเจ็กต์เครื่องหมาย
ประกาศตัวแปรเครื่องหมายใหม่ชื่อ mapMarker
ที่ด้านบนของบล็อกโค้ด struct
ใน MarkerDemo.swift
วางคำจำกัดความในบรรทัดใต้ประกาศ camera
โค้ดตัวอย่างนี้จะเริ่มต้นพร็อพเพอร์ตี้ทั้งหมดที่ใช้ได้
@State var mapMarker: Marker = .init(
position: .init(
latitude: 37.8044862,
longitude: -122.4301493,
altitude: 0.0),
altitudeMode: .absolute,
collisionBehavior: .required,
extruded: false,
drawsWhenOccluded: true,
sizePreserved: true,
zIndex: 0,
label: "Test"
)
เพิ่มเครื่องหมายลงในแผนที่
หากต้องการวาดเครื่องหมาย ให้เพิ่มเครื่องหมายนั้นลงในการปิดที่เรียกใช้เมื่อสร้างแผนที่
struct MarkerDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
mapMarker
}
}
}
}
เพิ่ม NavigationLink
ใหม่ไปยัง GoogleMaps3DDemoApp.swift
โดยมีปลายทางเป็น MarkerDemo()
และ Text
อธิบายว่า "การสาธิตเครื่องหมาย"
...
NavigationView {
List {
NavigationLink(destination: Map()) {
Text("Basic Map")
}
NavigationLink(destination: CameraDemo()) {
Text("Camera Demo")
}
NavigationLink(destination: MarkerDemo()) {
Text("Marker Demo")
}
}
}
...
ดูตัวอย่างและเรียกใช้แอป
รีเฟรชตัวอย่างหรือเรียกใช้แอปเพื่อดูเครื่องหมาย
เครื่องหมายแบบยื่นออกมา
วางเครื่องหมายเหนือพื้นหรือเมช 3 มิติได้โดยใช้ altitude
และ altitudeMode
คัดลอกการประกาศ mapMarker
ใน MarkerDemo.swift
ไปยังตัวแปร Marker
ใหม่ชื่อ extrudedMarker
ตั้งค่า altitude
เป็นค่าที่ไม่ใช่ 0 โดย 50 ก็เพียงพอแล้ว
เปลี่ยน altitudeMode
เป็น .relativeToMesh
และตั้งค่า extruded
เป็น true
ใช้ latitude
และ longitude
จากข้อมูลโค้ดที่นี่เพื่อวางเครื่องหมายบนยอดตึกสูง
@State var extrudedMarker: Marker = .init(
position: .init(
latitude: 37.78980534,
longitude: -122.3969349,
altitude: 50.0),
altitudeMode: .relativeToMesh,
collisionBehavior: .required,
extruded: true,
drawsWhenOccluded: true,
sizePreserved: true,
zIndex: 0,
label: "Extruded"
)
เรียกใช้หรือแสดงตัวอย่างแอปอีกครั้ง เครื่องหมายควรปรากฏบนอาคาร 3 มิติ
7. เพิ่มโมเดลลงในแผนที่
คุณสามารถเพิ่ม Model
ได้โดยใช้วิธีเดียวกับ Marker
คุณจะต้องมีไฟล์โมเดลที่เข้าถึงได้โดยใช้ URL หรือเพิ่มเป็นไฟล์ในเครื่องในโปรเจ็กต์ ในขั้นตอนนี้ เราจะใช้ไฟล์ในเครื่องซึ่งคุณสามารถดาวน์โหลดได้จากที่เก็บ GitHub สําหรับโค้ดแล็บนี้
เพิ่มไฟล์โมเดลลงในโปรเจ็กต์
สร้างโฟลเดอร์ใหม่ในโปรเจ็กต์ Xcode ชื่อ Models
ดาวน์โหลดโมเดลจากที่เก็บแอปตัวอย่างของ GitHub เพิ่มลงในโปรเจ็กต์โดยลากไปยังโฟลเดอร์ใหม่ในมุมมองโปรเจ็กต์ Xcode
ตรวจสอบว่าคุณได้ตั้งค่าเป้าหมายเป็นเป้าหมายหลักสําหรับแอป
ตรวจสอบการตั้งค่าระยะการสร้าง > คัดลอกทรัพยากร Bundle สำหรับโปรเจ็กต์ ไฟล์โมเดลควรอยู่ในรายการทรัพยากรที่คัดลอกไปยังกลุ่ม หากไม่เห็น ให้คลิก "+" เพื่อเพิ่ม
เพิ่มโมเดลลงในแอป
สร้างไฟล์ SwiftUI ใหม่ชื่อ ModelDemo.swift
เพิ่มคำสั่ง import
สำหรับ SwiftUI
และ GoogleMaps3D
เช่นเดียวกับในขั้นตอนก่อนหน้า
ประกาศ Map
ภายใน VStack
ใน body
import SwiftUI
import GoogleMaps3D
struct ModelDemo: View {
@State var camera: Camera = .sanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
รับเส้นทางโมเดลจาก Bundle เพิ่มโค้ดนี้ไว้นอก struct
private let fileUrl = Bundle.main.url(forResource: "balloon", withExtension: "glb")
ประกาศตัวแปรสําหรับโมเดลภายในโครงสร้าง
ระบุค่าเริ่มต้นในกรณีที่ไม่ได้ระบุ fileUrl
@State var balloonModel: Model = .init(
position: .init(
latitude: 37.791376,
longitude: -122.397571,
altitude: 300.0),
url: URL(fileURLWithPath: fileUrl?.relativePath ?? ""),
altitudeMode: .absolute,
scale: .init(x: 5, y: 5, z: 5),
orientation: .init(heading: 0, tilt: 0, roll: 0)
)
3. ใช้โมเดลกับแผนที่
เช่นเดียวกับการเพิ่ม Marker
เพียงระบุข้อมูลอ้างอิงถึง Model
ในการประกาศ Map
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
balloonModel
}
}
}
ดูตัวอย่างและเรียกใช้แอป
เพิ่ม NavigationLink
ใหม่ไปยัง GoogleMaps3DDemoApp.swift
โดยมีปลายทางเป็น ModelDemo()
และ Text
"Model Demo"
...
NavigationLink(destination: ModelDemo()) {
Text("Model Demo")
}
...
รีเฟรชตัวอย่างหรือเรียกใช้แอปเพื่อดูโมเดล
8. วาดเส้นและรูปหลายเหลี่ยมบนแผนที่
ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีเพิ่มเส้นและรูปร่างรูปหลายเหลี่ยมลงในแผนที่ 3 มิติ
คุณจะกําหนดรูปทรงเป็นอาร์เรย์ของออบเจ็กต์ LatLngAltitude
เพื่อลดความซับซ้อน ในแอปพลิเคชันจริง ระบบอาจโหลดข้อมูลจากไฟล์ การเรียก API หรือฐานข้อมูล
สร้างออบเจ็กต์รูปร่างเพื่อจัดการข้อมูลรูปร่าง
เพิ่มคําจํากัดความ Camera
ใหม่ลงใน MapHelpers.swift
ที่มองไปที่ใจกลางเมืองซานฟรานซิสโก
public static var downtownSanFrancisco: Camera = .init(latitude: 37.7905, longitude: -122.3989, heading: 25, tilt: 71, range: 2500)
เพิ่มไฟล์ใหม่ลงในโปรเจ็กต์ชื่อ ShapesDemo.swift
เพิ่ม struct
ชื่อ ShapesDemo
ที่ใช้โปรโตคอล View
และเพิ่ม body
ลงใน struct
struct ShapesDemo: View {
@State var camera: Camera = .downtownSanFrancisco
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
}
}
}
}
คลาสที่คุณจะใช้จัดการข้อมูลรูปร่างคือ Polyline
และ Polygon
เปิด ShapesDemo.swift
แล้วเพิ่มลงใน struct
ดังนี้
var polyline: Polyline = .init(coordinates: [
LatLngAltitude(latitude: 37.80515638571346, longitude: -122.4032569467164, altitude: 0),
LatLngAltitude(latitude: 37.80337073509504, longitude: -122.4012878349353, altitude: 0),
LatLngAltitude(latitude: 37.79925208843463, longitude: -122.3976697250461, altitude: 0),
LatLngAltitude(latitude: 37.7989102378512, longitude: -122.3983408725656, altitude: 0),
LatLngAltitude(latitude: 37.79887832784348, longitude: -122.3987094864192, altitude: 0),
LatLngAltitude(latitude: 37.79786443410338, longitude: -122.4066878788802, altitude: 0),
LatLngAltitude(latitude: 37.79549248916587, longitude: -122.4032992702785, altitude: 0),
LatLngAltitude(latitude: 37.78861484290265, longitude: -122.4019489189814, altitude: 0),
LatLngAltitude(latitude: 37.78618687561075, longitude: -122.398969592545, altitude: 0),
LatLngAltitude(latitude: 37.7892310309145, longitude: -122.3951458683092, altitude: 0),
LatLngAltitude(latitude: 37.7916358762409, longitude: -122.3981969390652, altitude: 0)
])
.stroke(GoogleMaps3D.Polyline.StrokeStyle(
strokeColor: UIColor(red: 0.09803921568627451, green: 0.403921568627451, blue: 0.8235294117647058, alpha: 1),
strokeWidth: 10.0,
outerColor: .white,
outerWidth: 0.2
))
.contour(GoogleMaps3D.Polyline.ContourStyle(isGeodesic: true))
var originPolygon: Polygon = .init(outerCoordinates: [
LatLngAltitude(latitude: 37.79165766856578, longitude: -122.3983762901255, altitude: 300),
LatLngAltitude(latitude: 37.7915324439261, longitude: -122.3982171091383, altitude: 300),
LatLngAltitude(latitude: 37.79166617650914, longitude: -122.3980478493319, altitude: 300),
LatLngAltitude(latitude: 37.79178986470217, longitude: -122.3982041104199, altitude: 300),
LatLngAltitude(latitude: 37.79165766856578, longitude: -122.3983762901255, altitude: 300 )
],
altitudeMode: .relativeToGround)
.style(GoogleMaps3D.Polygon.StyleOptions(fillColor:.green, extruded: true) )
var destinationPolygon: Polygon = .init(outerCoordinates: [
LatLngAltitude(latitude: 37.80515661739527, longitude: -122.4034307490334, altitude: 300),
LatLngAltitude(latitude: 37.80503794515428, longitude: -122.4032633416024, altitude: 300),
LatLngAltitude(latitude: 37.80517850164195, longitude: -122.4031056058006, altitude: 300),
LatLngAltitude(latitude: 37.80529346901115, longitude: -122.4032622466595, altitude: 300),
LatLngAltitude(latitude: 37.80515661739527, longitude: -122.4034307490334, altitude: 300 )
],
altitudeMode: .relativeToGround)
.style(GoogleMaps3D.Polygon.StyleOptions(fillColor:.red, extruded: true) )
สังเกตพารามิเตอร์การเริ่มต้นที่ใช้
altitudeMode: .relativeToGround
ใช้เพื่อยื่นรูปหลายเหลี่ยมให้สูงขึ้นจากพื้นตามระดับที่ต้องการaltitudeMode: .clampToGround
ใช้เพื่อทำให้เส้นประกอบเป็นไปตามรูปร่างของพื้นผิวโลก- รูปแบบได้รับการตั้งค่าในออบเจ็กต์
Polygon
โดยการต่อเชื่อมการเรียกใช้เมธอดกับstyleOptions()
หลังจากเรียกใช้.init()
เพิ่มรูปร่างลงในแผนที่
เช่นเดียวกับในขั้นตอนก่อนหน้า คุณสามารถเพิ่มรูปร่างลงในส่วนปิดท้ายของ Map
ได้โดยตรง สร้าง Map
ภายใน VStack
...
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid) {
polyline
originPolygon
destinationPolygon
}
}
}
...
ดูตัวอย่างและเรียกใช้แอป
เพิ่มโค้ดเวอร์ชันตัวอย่างและตรวจสอบแอปในบานหน้าต่างแสดงตัวอย่างใน Xcode
#Preview {
ShapesDemo()
}
หากต้องการเรียกใช้แอป ให้เพิ่ม NavigationLink
ใหม่ลงใน GoogleMaps3DDemoApp.swift
ซึ่งจะเปิดมุมมองเดโมใหม่
...
NavigationLink(destination: ShapesDemo()) {
Text("Shapes Demo")
}
...
เรียกใช้แอปและสำรวจรูปร่างที่คุณเพิ่ม
9. จัดการเหตุการณ์การแตะเครื่องหมายสถานที่
ในขั้นตอนนี้ คุณจะได้เรียนรู้วิธีตอบสนองต่อการแตะเครื่องหมายตำแหน่งของผู้ใช้
หมายเหตุ: หากต้องการดูเครื่องหมายสถานที่บนแผนที่ คุณจะต้องตั้งค่า MapMode
เป็น .hybrid
การจัดการการแตะต้องใช้เมธอด Map.onPlaceTap
เหตุการณ์ onPlaceTap
มีออบเจ็กต์ PlaceTapInfo
ที่คุณใช้รับรหัสสถานที่ของเครื่องหมายสถานที่ที่แตะได้
คุณสามารถใช้รหัสสถานที่เพื่อค้นหารายละเอียดเพิ่มเติมได้โดยใช้ Places SDK หรือ Places API
เพิ่ม Swift View ใหม่
เพิ่มโค้ดต่อไปนี้ลงในไฟล์ Swift ใหม่ชื่อ PlaceTapDemo.swift
import GoogleMaps3D
import SwiftUI
struct PlaceTapDemo: View {
@State var camera: Camera = .sanFrancisco
@State var isPresented = false
@State var tapInfo: PlaceTapInfo?
var body: some View {
Map(camera: $camera, mode: .hybrid)
.onPlaceTap { tapInfo in
self.tapInfo = tapInfo
isPresented.toggle()
}
.alert(
"Place tapped - \(tapInfo?.placeId ?? "nil")",
isPresented: $isPresented,
actions: { Button("OK") {} }
)
}
}
#Preview {
PlaceTapDemo()
}
ดูตัวอย่างและเรียกใช้แอป
เปิดช่องแสดงตัวอย่างเพื่อดูตัวอย่างแอป
หากต้องการเรียกใช้แอป ให้เพิ่ม NavigationLink
ใหม่ลงใน GoogleMaps3DDemoApp.swift
...
NavigationLink(destination: PlaceTapDemo()) {
Text("Place Tap Demo")
}
...
10. (ไม่บังคับ) ดำเนินการต่อ
ภาพเคลื่อนไหวขั้นสูงของกล้อง
Use Case บางรายการต้องใช้ภาพเคลื่อนไหวที่ราบรื่นตามลำดับหรือรายการตำแหน่งหรือสถานะของกล้อง เช่น โปรแกรมจำลองการบิน หรือการดูการเดินป่าหรือการวิ่งซ้ำ
ในขั้นตอนนี้ คุณจะได้ดูวิธีโหลดรายการสถานที่จากไฟล์ และแสดงภาพเคลื่อนไหวผ่านสถานที่แต่ละแห่งตามลำดับ
โหลดไฟล์ที่มีลําดับสถานที่
ดาวน์โหลด flightpath.json
จากที่เก็บแอปตัวอย่างของ GitHub
สร้างโฟลเดอร์ใหม่ในโปรเจ็กต์ Xcode ชื่อ JSON
ลาก flightpath.json
ไปยังโฟลเดอร์ JSON
ใน Xcode
กำหนดเป้าหมายให้เป็นผู้ชมเป้าหมายหลักของแอป ตรวจสอบว่าการตั้งค่าทรัพยากร App Bundle ของโปรเจ็กต์มีไฟล์นี้
สร้างไฟล์ Swift ใหม่ 2 ไฟล์ในแอปชื่อ FlightPathData.swift
และ FlightDataLoader.swift
คัดลอกโค้ดต่อไปนี้ลงในแอป โค้ดนี้จะสร้างโครงสร้างและคลาสที่อ่านไฟล์ในเครื่องชื่อ "flighpath.json" และถอดรหัสเป็น JSON
โครงสร้าง FlightPathData
และ FlightPathLocation
จะแสดงโครงสร้างข้อมูลในไฟล์ JSON เป็นออบเจ็กต์ Swift
คลาส FlightDataLoader
จะอ่านข้อมูลจากไฟล์และถอดรหัส โดยจะใช้โปรโตคอล ObservableObject
เพื่อให้แอปของคุณสังเกตการเปลี่ยนแปลงของข้อมูลได้
ระบบจะแสดงข้อมูลที่แยกวิเคราะห์ผ่านพร็อพเพอร์ตี้ที่เผยแพร่
FlightPaths.swift
import GoogleMaps3D
struct FlightPathData: Decodable {
let flight: [FlightPathLocation]
}
struct FlightPathLocation: Decodable {
let timestamp: Int64
let latitude: Double
let longitude: Double
let altitude: Double
let bearing: Double
let speed: Double
}
FlightDataLoader.swift
import Foundation
public class FlightDataLoader : ObservableObject {
@Published var flightPathData: FlightPathData = FlightPathData(flight:[])
@Published var isLoaded: Bool = false
public init() {
load("flightpath.json")
}
public func load(_ path: String) {
if let url = Bundle.main.url(forResource: path, withExtension: nil){
if let data = try? Data(contentsOf: url){
let jsondecoder = JSONDecoder()
do{
let result = try jsondecoder.decode(FlightPathData.self, from: data)
flightPathData = result
isLoaded = true
}
catch {
print("Error trying to load or parse the JSON file.")
}
}
}
}
}
สร้างภาพเคลื่อนไหวของกล้องไปตามแต่ละตำแหน่ง
หากต้องการทำให้กล้องเคลื่อนไหวระหว่างลำดับขั้นตอนต่างๆ คุณจะใช้ KeyframeAnimator
ระบบจะสร้าง Keyframe
แต่ละรายการเป็น CubicKeyframe
เพื่อให้การเปลี่ยนแปลงสถานะของกล้องแสดงเป็นภาพเคลื่อนไหวอย่างราบรื่น
การใช้ flyCameraTo()
จะทำให้มุมมอง "สลับ" ระหว่างสถานที่แต่ละแห่ง
ก่อนอื่นให้ประกาศกล้องชื่อ "innsbruck" ใน MapHelpers.swift
public static var innsbruck: Camera = .init(
latitude: 47.263,
longitude: 11.3704,
altitude: 640.08,
heading: 237,
tilt: 80.0,
roll: 0.0,
range: 200)
ตอนนี้ให้ตั้งค่ามุมมองใหม่ในไฟล์ใหม่ชื่อ FlyAlongRoute.swift
นําเข้า SwiftUI
และ GoogleMaps3D
เพิ่ม Map
และ Button
ไว้ใน VStack
ตั้งค่า Button
เพื่อสลับสถานะของตัวแปรบูลีน animation
ประกาศออบเจ็กต์ State
สำหรับ FlightDataLoader
ซึ่งจะโหลดไฟล์ JSON เมื่อเริ่มต้น
import GoogleMaps3D
import SwiftUI
struct FlyAlongRoute: View {
@State private var camera: Camera = .innsbruck
@State private var flyToDuration: TimeInterval = 5
@State var animation: Bool = true
@StateObject var flightData: FlightDataLoader = FlightDataLoader()
var body: some View {
VStack {
Map(camera: $camera, mode: .hybrid)
Button("Fly Along Route"){
animation.toggle()
}
}
}
}
สร้างคีย์เฟรม
ขั้นตอนพื้นฐานคือการสร้างฟังก์ชันที่แสดงผลเฟรมใหม่ในลำดับภาพเคลื่อนไหว เฟรมใหม่แต่ละเฟรมจะกำหนดสถานะกล้องถัดไปเพื่อให้นักสร้างภาพเคลื่อนไหวใช้สร้างภาพเคลื่อนไหว เมื่อสร้างฟังก์ชันนี้แล้ว ให้เรียกใช้ฟังก์ชันนั้นกับสถานที่แต่ละแห่งจากไฟล์ตามลำดับ
เพิ่มฟังก์ชัน 2 รายการลงในโครงสร้าง FlyAlongRoute
ฟังก์ชัน makeKeyFrame
จะแสดงผล CubicKeyframe
ที่มีสถานะกล้อง ฟังก์ชัน makeCamera
จะนําขั้นตอนในลําดับข้อมูลเที่ยวบินไปแสดงผลออบเจ็กต์ Camera
ที่แสดงขั้นตอนนั้น
func makeKeyFrame(step: FlightPathLocation) -> CubicKeyframe<Camera> {
return CubicKeyframe(
makeCamera(step: step),
duration: flyToDuration
)
}
func makeCamera(step: FlightPathLocation) -> Camera {
return .init(
latitude: step.latitude,
longitude: step.longitude,
altitude: step.altitude,
heading: step.bearing,
tilt: 75,
roll: 0,
range: 200
)
}
ใส่ภาพเคลื่อนไหวเข้าด้วยกัน
เรียกใช้ keyframeAnimator
หลังจากการเริ่มต้น Map
และตั้งค่าเริ่มต้น
คุณจะต้องมีสถานะกล้องเริ่มต้นตามตำแหน่งแรกในเส้นทางการบิน
ภาพเคลื่อนไหวควรทริกเกอร์ตามสถานะที่เปลี่ยนแปลงของตัวแปร
เนื้อหา keyframeAnimator
ควรเป็นแผนที่
รายการคีย์เฟรมจริงสร้างขึ้นโดยการวนดูแต่ละตำแหน่งในเส้นทางการบิน
VStack {
Map(camera: $camera, mode: .hybrid)
.keyframeAnimator(
initialValue: makeCamera(step: flightData.flightPathData.flight[0]),
trigger: animation,
content: { view, value in
Map(camera: .constant(value), mode: .hybrid)
},
keyframes: { _ in
KeyframeTrack(content: {
for i in 1...flightData.flightPathData.flight.count-1 {
makeKeyFrame(step: flightData.flightPathData.flight[i])
}
})
}
)
}
ดูตัวอย่างและเรียกใช้แอป
เปิดบานหน้าต่างแสดงตัวอย่างเพื่อดูตัวอย่างมุมมอง
เพิ่ม NavigationLink
ใหม่ที่มีปลายทางเป็น FlightPathDemo()
ไปยัง GoogleMaps3DDemoApp.swift
แล้วเรียกใช้แอปเพื่อลองใช้
11. ขอแสดงความยินดี
คุณสร้างแอปพลิเคชันที่มีคุณสมบัติต่อไปนี้เรียบร้อยแล้ว
- เพิ่มแผนที่ 3 มิติพื้นฐานลงในแอป
- เพิ่มเครื่องหมาย เส้น รูปหลายเหลี่ยม และโมเดลลงในแผนที่
- ใช้โค้ดเพื่อควบคุมกล้องให้บินผ่านแผนที่และรอบๆ สถานที่ที่เฉพาะเจาะจง
สิ่งที่คุณได้เรียนรู้
- วิธีเพิ่มแพ็กเกจ
GoogleMaps3D
ลงในแอป SwiftUI ของ Xcode - วิธีเริ่มต้นใช้งานแผนที่ 3 มิติด้วยคีย์ API และมุมมองเริ่มต้น
- วิธีเพิ่มเครื่องหมาย โมเดล 3 มิติ เส้น และรูปหลายเหลี่ยมลงในแผนที่
- วิธีควบคุมกล้องเพื่อแสดงภาพเคลื่อนไหวไปยังตำแหน่งอื่น
- วิธีจัดการเหตุการณ์การคลิกบนเครื่องหมายสถานที่
ขั้นตอนถัดไปคือ
- ดูรายละเอียดเพิ่มเติมเกี่ยวกับสิ่งที่คุณทำได้ด้วย Maps 3D SDK สำหรับ iOS ได้ในคู่มือนักพัฒนาซอฟต์แวร์
- ช่วยเราสร้างเนื้อหาที่คุณจะพบว่ามีประโยชน์มากที่สุดโดยตอบแบบสํารวจต่อไปนี้