วงจรและเหตุการณ์ของ MapView
แผนที่จัดการโดยใช้สองออบเจ็กต์: มุมมองและออบเจ็กต์สถานะ สถานะ (mapViewState) เป็นจุดเชื่อมต่อสำหรับกล้อง การออกแบบ และการโต้ตอบ ส่วนมุมมองเพียงวางไว้ในต้นไม้ UI ของแต่ละแพลตฟอร์ม การเริ่มต้นผ่านขั้นตอนทั่วไป และการโหลดเสร็จสิ้นรวมถึงการดำเนินการของผู้ใช้จะได้รับผ่านเหตุการณ์
01 · mapViewState
mapViewState เป็นออบเจ็กต์สถานะที่สอดคล้องกับแผนที่หน้าเดียว มีการใช้งานเฉพาะสำหรับแต่ละผู้ให้บริการ แต่สมาชิกสาธารณะเป็นสิ่งทั่วไป โค้ดแอปเพียงดูที่อินเทอร์เฟซทั่วไปก็เพียงพอแล้ว
สถานะมีอายุการใช้งานนานกว่ามุมมอง แม้ว่ามุมมองจะถูกสร้างขึ้นใหม่ ตำแหน่งกล้องและการออกแบบจะยังคงอยู่ที่ฝั่งสถานะ ดังนั้นแผนที่จะถูกคืนค่าเหมือนเดิม
// สร้างสถานะด้วย remember* แผนที่เดิมจึงคงอยู่แม้หมุนหน้าจอ
val mapViewState =
rememberGoogleMapViewState(
mapDesign = GoogleMapDesign.Normal,
cameraPosition = initCameraPosition,
)
GoogleMapView(state = mapViewState, modifier = Modifier.fillMaxSize())// เป็น ObservableObject ให้ View ถือไว้ด้วย @StateObject
@StateObject private var mapLibreState = MapLibreViewState(
mapDesignType: MapLibreDesign.OsmBright,
cameraPosition: viewModel.initCameraPosition
)
MapLibreMapView(state: mapLibreState) { MapViewContent() }const [mapViewState, setMapViewState] =
useState<MapViewStateInterface<MapDesignTypeInterface<unknown>> | null>(null);
// MapViewContainer คือแรปเปอร์สลับผู้ให้บริการของแอปตัวอย่าง ไม่ได้มากับ SDK
<MapViewContainer provider={provider} cameraPosition={INIT_CAMERA} onStateReady={setMapViewState}>
<Markers states={markerStates} />
</MapViewContainer>02 · วงจรการเริ่มต้น
การเริ่มต้นแผนที่ผ่านขั้นตอนเดียวกันในทุกผู้ให้บริการ: การโหลด SDK การสร้างมุมมอง การสร้างอินสแตนซ์แผนที่ และการวาดไทล์เสร็จสิ้น เนื่องจากขั้นตอนถูกรวมเป็น InitState คุณไม่ต้องจำโดยผู้ให้บริการว่าเมื่อใดยังไม่ควรโต้ตอบ
การเคลื่อนไหวของกล้องและการเพิ่มซ้อนทับจะได้รับตั้งแต่ MapCreated และจะถูกจัดคิวภายใน หากคุณต้องการดำเนินการหลังจากการโหลดเสร็จสิ้น ให้ใช้ onMapLoaded
โหลด SDK แผนที่ บนเว็บใช้การฉีดสคริปต์ บนมือถือใช้กระบวนการเริ่มต้น หากล้มเหลวจะไปที่ Failed
ห่อหุ้มอินสแตนซ์แผนที่เนทีฟด้วยโฮลเดอร์ จากนี้ไป ประเภทเฉพาะของ SDK จะถูกซ่อนอยู่ที่นี่
ห่อหุ้มโฮลเดอร์ด้วยตัวควบคุม และเตรียม API ทั่วไปและการเชื่อมต่อเหตุการณ์ ตัวควบคุมจะเชื่อมต่อกับสถานะ
ข้ามการหมุนหน้าจอและการสร้างใหม่
บน Android สถานะจะถูกบันทึกด้วย rememberSaveable หลังจากการหมุนหน้าจอหรือการเปลี่ยนการกำหนดค่า ตำแหน่งกล้องและการออกแบบจะถูกคืนค่า ในการเปลี่ยนแปลงการกำหนดค่า มุมมองแผนที่เองจะไม่ถูกทำลาย แต่จะถูกนำกลับมาใช้ใหม่
เมื่อถูกทำลาย
เมื่อทำลายจริง (ออกจากหน้าจอ) การจัดการโอเวอร์เลย์ เส้นทางของเซิร์ฟเวอร์ไทล์ และขอบเขตของคอรูทีนที่ตัวควบคุมถืออยู่จะถูกปล่อยออกพร้อมกัน เมื่อสลับผู้ให้บริการ แผนที่เก่าจะถูกทำความสะอาดผ่านเส้นทางเดียวกัน
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() }
}03 · เหตุการณ์
ตัวจัดการที่ส่งผ่านไปยังมุมมองมีโครงสร้างเหมือนกันในทั้งสามแพลตฟอร์ม ประเภทก็เป็นสิ่งทั่วไป: การโหลดเสร็จสิ้นได้รับออบเจ็กต์สถานะ การแตะได้รับพิกัด การเปลี่ยนกล้องได้รับตำแหน่งกล้อง
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 */ }MapLibreMapView(
state: mapLibreState,
onMapLoaded: { state in viewModel.onMapLoaded(state) },
onCameraMoveStart: viewModel.onMapCameraMoveStart,
onCameraMove: viewModel.onCameraChanged,
onCameraMoveEnd: viewModel.onMapCameraMoveEnd
) {
MapViewContent()
}<MapViewContainer
provider={provider}
cameraPosition={INIT_CAMERA}
onMapClick={() => setSelected(null)}
onCameraMove={setCameraPosition}
>
<Markers states={markerStates} />
</MapViewContainer>เหตุการณ์ที่เกี่ยวข้องกับกล้องจะอัปเดต cameraPosition ของวัตถุสถานะพร้อมกัน ดังนั้นสามารถอ่านกล้องล่าสุดได้เสมอโดยไม่ต้องแนบตัวจัดการ หากคุณต้องการหลีกเลี่ยงการดึงข้อมูลซ้ำระหว่างการเคลื่อนที่ ให้ใช้เฉพาะ onCameraMoveEnd
04 · ทางออกสู่ Native
สำหรับกรณีที่ API ทั่วไปไม่เพียงพอ เราได้เตรียมทางลงไปยังอินสแตนซ์แผนที่แบบเนทีฟไว้ โดยปกติจะไม่ใช้ แต่เป็นทางออกเมื่อคุณต้องการใช้ฟีเจอร์เฉพาะของผู้ให้บริการเพียงที่เดียว
โฮลเดอร์ที่ห่อหุ้มแผนที่เนทีฟ
โฮลเดอร์มีสององค์ประกอบ: มุมมองของแพลตฟอร์มและอินสแตนซ์แผนที่ โค้ดเฉพาะของ SDK จะถูกกักกันตั้งแต่ตรงนี้ไป และไม่รั่วไหลไปยังโค้ดทั่วไป
การแปลงระหว่างพิกัดและตำแหน่งบนหน้าจอ
พิกัดภูมิศาสตร์และตำแหน่งพิกเซลบนหน้าจอสามารถแปลงระหว่างกันได้ ใช้เมื่อวาง UI แบบกำหนดเองไว้บนแผนที่
// ดึงออกมาเฉพาะตอนที่จำเป็นต้องใช้ API เนทีฟจริง ๆ val holder = mapViewState.getMapViewHolder() val nativeMap = holder?.map // GoogleMap / MapLibreMap / ... val offset = holder?.toScreenOffset(point)
if let holder = mapViewState.getMapViewHolder() {
let nativeMap = holder.map
let offset = holder.toScreenOffset(position: point)
}const holder = mapViewState.getMapViewHolder(); const nativeMap = holder?.map; // google.maps.Map / maplibregl.Map / ...
โค้ดที่ใช้ตัวถือขึ้นอยู่กับผู้ให้บริการ โปรดแยกส่วนที่คุณต้องการให้เหมือนกันทั่วไปกับส่วนที่คุณตั้งใจใช้ API เฉพาะให้ชัดเจน