เอกสาร / มุมมองแผนที่ / MapView และสถานะ

วงจรและเหตุการณ์ของ MapView

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

ANDROID
MapViewStateInterface
iOS
MapViewStateProtocol
REACT
MapViewStateInterface
แพลตฟอร์ม

01 · mapViewState

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

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

สมาชิก
คำอธิบาย
id
ตัวระบุของสถานะ ชี้ไปที่แผนที่เดิมต่อไปแม้ว่ามุมมองจะถูกสร้างขึ้นใหม่
cameraPosition
ตำแหน่งกล้องปัจจุบัน พื้นที่ที่มองเห็น (visibleRegion) ยังสามารถรับได้จากที่นี่
mapDesignType
การออกแบบแผนที่ปัจจุบัน เมื่อกำหนดค่าจะเปลี่ยนทันที
moveCameraTo()
ย้ายกล้อง หากส่งผ่านระยะเวลาจะมีการเคลื่อนไหว
fitBounds()
ปรับกล้องให้พอดีกับช่วงที่ระบุ บนทั้งสามแพลตฟอร์มเป็นเมธอดของออบเจ็กต์สถานะ และมอบหมายให้คอนโทรลเลอร์ภายใน
getMapViewHolder()
ส่งคืนโฮลเดอร์ที่ห่อหุ้มอินสแตนซ์แผนที่เนทีฟ
MapViewState · Jetpack Compose
// สร้างสถานะด้วย remember* แผนที่เดิมจึงคงอยู่แม้หมุนหน้าจอ
val mapViewState =
    rememberGoogleMapViewState(
        mapDesign = GoogleMapDesign.Normal,
        cameraPosition = initCameraPosition,
    )

GoogleMapView(state = mapViewState, modifier = Modifier.fillMaxSize())

02 · วงจรการเริ่มต้น

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

การเคลื่อนไหวของกล้องและการเพิ่มซ้อนทับจะได้รับตั้งแต่ MapCreated และจะถูกจัดคิวภายใน หากคุณต้องการดำเนินการหลังจากการโหลดเสร็จสิ้น ให้ใช้ onMapLoaded

ภาพ · ลำดับการเปลี่ยนของ InitState
NotStarted
ยังไม่มีอะไรเริ่มทำงาน
Initializing
เริ่มการเริ่มต้นระบบ ตรวจสอบคีย์และโหลด SDK
SdkInitialized
โหลดตัว SDK แผนที่เสร็จแล้ว
MapViewCreated
สร้างวิวของแพลตฟอร์มแล้ว (MapView / UIView / DOM element)
MapCreating
กำลังสร้างอินสแตนซ์แผนที่ภายในวิว
MapCreated
อินสแตนซ์แผนที่พร้อมใช้งาน การสั่งกล้องและการเพิ่มโอเวอร์เลย์เริ่มมีผล
MapLoaded
วาดไทล์เสร็จแล้ว onMapLoaded ถูกเรียกในขั้นนี้
Failed
การเริ่มต้นระบบล้มเหลว เช่น คีย์ไม่ถูกต้องหรือไม่มีเครือข่าย
ขั้นตอนถูกประกาศเป็น enum ชุดเดียวกันทั้งบน Android, iOS และ React สิ่งที่ต้องรอจึงไม่เปลี่ยนแม้จะสลับผู้ให้บริการ
01 sdkInitialize

โหลด SDK แผนที่ บนเว็บใช้การฉีดสคริปต์ บนมือถือใช้กระบวนการเริ่มต้น หากล้มเหลวจะไปที่ Failed

02 createHolder

ห่อหุ้มอินสแตนซ์แผนที่เนทีฟด้วยโฮลเดอร์ จากนี้ไป ประเภทเฉพาะของ SDK จะถูกซ่อนอยู่ที่นี่

03 createController

ห่อหุ้มโฮลเดอร์ด้วยตัวควบคุม และเตรียม API ทั่วไปและการเชื่อมต่อเหตุการณ์ ตัวควบคุมจะเชื่อมต่อกับสถานะ

RESTORE

ข้ามการหมุนหน้าจอและการสร้างใหม่

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

TEARDOWN

เมื่อถูกทำลาย

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

การใช้งานในวิดีโอ · Android + MapLibreKotlin · Jetpack Compose
var ready by remember { mutableStateOf(false) }

MapLibreMapView(
    state = mapViewState,
    // Called once, when the tiles have finished drawing
    onMapLoaded = { state ->
        ready = true
        state.fitBounds(routeBounds, padding = 48)
    },
) {
    // Declarations here are not lost before MapCreated — they are queued internally
    Marker(markerState)
}

if (!ready) {
    // Your own loading overlay, if you want one. The map does not need blocking
    Box(Modifier.fillMaxSize()) { CircularProgressIndicator() }
}
วิดีโอตัวอย่าง · ความคืบหน้าของการเริ่มต้น
ยังไม่ได้ถ่ายวิดีโอวิธีที่ InitState ดำเนินไปทีละขั้นตอนตั้งแต่สร้างแผนที่จนถึงการยอมรับการโต้ตอบ จุดเปลี่ยนจากการแสดงการโหลดสามารถเห็นได้ชัดเจน

03 · เหตุการณ์

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

เหตุการณ์
ค่าที่ได้รับ
คำอธิบาย
onMapLoaded
MapViewState
การโหลดแผนที่เสร็จสมบูรณ์ มาตรฐานคือเก็บวัตถุสถานะจากอาร์กิวเมนต์ไว้และใช้สำหรับการดำเนินการต่อไป
onMapClick
GeoPoint
การแตะที่แผนที่ เช่น เพื่อปิดบับเบิลข้อมูล วางหมุด ฯลฯ
onMapLongClick
GeoPoint
การกดค้าง
onCameraMoveStart
MapCameraPosition
เริ่มต้นการควบคุมกล้อง จะถูกเรียกทั้งจากการโต้ตอบของผู้ใช้และการเคลื่อนที่โดยโปรแกรม
onCameraMove
MapCameraPosition
จะถูกเรียกอย่างต่อเนื่องระหว่างการเคลื่อนที่ เช่น สำหรับการแสดงพิกัดที่กำลังแสดง ฯลฯ
onCameraMoveEnd
MapCameraPosition
เมื่อการเคลื่อนที่หยุดลง การดึงข้อมูลซ้ำโดยพื้นฐานควรทำที่นี่
GoogleMapView · การรับเหตุการณ์
GoogleMapView(
    state = mapViewState,
    onMapLoaded = { state -> viewModel.onMapLoaded(state) },
    onMapClick = { point -> viewModel.onMapClick(point) },
    onCameraMove = { camera -> viewModel.onCameraChanged(camera) },
    onCameraMoveEnd = { camera -> viewModel.onCameraSettled(camera) },
) { /* markers, overlays */ }

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

04 · ทางออกสู่ Native

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

MapViewHolder

โฮลเดอร์ที่ห่อหุ้มแผนที่เนทีฟ

โฮลเดอร์มีสององค์ประกอบ: มุมมองของแพลตฟอร์มและอินสแตนซ์แผนที่ โค้ดเฉพาะของ SDK จะถูกกักกันตั้งแต่ตรงนี้ไป และไม่รั่วไหลไปยังโค้ดทั่วไป

toScreenOffset / fromScreenOffset

การแปลงระหว่างพิกัดและตำแหน่งบนหน้าจอ

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

การดึงตัวถือ
// ดึงออกมาเฉพาะตอนที่จำเป็นต้องใช้ API เนทีฟจริง ๆ
val holder = mapViewState.getMapViewHolder()
val nativeMap = holder?.map // GoogleMap / MapLibreMap / ...
val offset = holder?.toScreenOffset(point)

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

หน้าที่เกี่ยวข้อง