MapView-Lebenszyklus und Ereignisse
Die Karte wird mit zwei Objekten behandelt: der Ansicht und dem Zustandsobjekt. Der Zustand (mapViewState) ist die Schnittstelle für Kamera, Design und Interaktion, während die Ansicht nur im UI-Baum der jeweiligen Plattform platziert wird. Die Initialisierung läuft durch gemeinsame Phasen, und das Laden abgeschlossen sowie Benutzeraktionen werden über Ereignisse empfangen.
01 · mapViewState
mapViewState ist ein Zustandsobjekt, das einer einzelnen Kartenfläche entspricht. Es gibt implementierungsspezifische Versionen pro Anbieter, aber die öffentlich zugänglichen Member sind gemeinsam; Anwendungscode muss nur die gemeinsame Schnittstelle beachten.
Der Zustand lebt länger als die Ansicht. Selbst wenn die Ansicht neu erstellt wird, verbleiben Kameraposition und Design auf der Zustandsseite, sodass die Karte unverändert wiederhergestellt wird.
// Den State mit remember* erzeugen, damit dieselbe Karte eine Drehung übersteht
val mapViewState =
rememberGoogleMapViewState(
mapDesign = GoogleMapDesign.Normal,
cameraPosition = initCameraPosition,
)
GoogleMapView(state = mapViewState, modifier = Modifier.fillMaxSize())// Ein ObservableObject: mit @StateObject an der View halten
@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 ist der Anbieter-Umschalter der Beispiel-App — nicht Teil des SDK
<MapViewContainer provider={provider} cameraPosition={INIT_CAMERA} onStateReady={setMapViewState}>
<Markers states={markerStates} />
</MapViewContainer>02 · Initialisierungslebenszyklus
Die Karteninitialisierung durchläuft auf allen Anbietern dieselben Phasen: Laden des SDK, Erzeugen der Ansicht, Erzeugen der Karteninstanz und Abschluss des Kachelns. Da die Phasen als InitState gemeinsam sind, müssen Sie nicht anbieterspezifisch merken, wann noch nicht interagiert werden darf.
Kamerabewegungen und das Hinzufügen von Overlays werden ab MapCreated akzeptiert und intern in eine Warteschlange gestellt. Wenn Sie erst nach Abschluss des Ladens etwas tun möchten, verwenden Sie onMapLoaded.
Lädt das Karten-SDK. Im Web per Skriptinjektion, auf Mobilgeräten per Initialisierung. Im Fehlerfall wird zu Failed gewechselt.
Umschließt die native Karteninstanz mit einem Holder. Ab hier sind SDK-spezifische Typen verborgen.
Umschließt den Holder mit einem Controller und stellt die gemeinsame API sowie die Event-Verdrahtung bereit. Der Controller wird mit dem Zustand verbunden.
Über Bildschirmrotation und Neuerstellung hinweg
Unter Android wird der Zustand mit rememberSaveable gespeichert; nach einer Bildschirmrotation oder Konfigurationsänderung werden Kameraposition und Design wiederhergestellt. Bei Konfigurationsänderungen wird die Kartenansicht selbst nicht zerstört, sondern wiederverwendet.
Wenn zerstört
Bei einer echten Zerstörung (Verlassen des Bildschirms) werden das Overlay-Management, die Routen des Kachel-Servers und der Coroutine-Scope, die der Controller hält, gemeinsam freigegeben. Auch beim Wechsel des Anbieters wird die alte Karte über denselben Pfad bereinigt.
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 · Ereignisse
Die Handler, die an die Ansicht übergeben werden, haben auf allen drei Plattformen dieselbe Struktur. Die Typen sind ebenfalls gemeinsam: Laden abgeschlossen empfängt das Zustandsobjekt, Tippen empfängt Koordinaten, Kameraänderung empfängt die Kameraposition.
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>Kamera-bezogene Ereignisse aktualisieren gleichzeitig cameraPosition des Statusobjekts, sodass die neueste Kamera immer gelesen werden kann, auch ohne Handler. Wenn Sie ein erneutes Abrufen während der Bewegung vermeiden möchten, verwenden Sie nur onCameraMoveEnd.
04 · Ausweg zu Native
Für den Fall, dass die gemeinsame API nicht ausreicht, haben wir eine Möglichkeit vorbereitet, auf die native Karteninstanz zuzugreifen. Normalerweise wird sie nicht verwendet, dient aber als Ausweg, wenn Sie eine anbieterspezifische Funktion nur an einer Stelle verwenden möchten.
Holder, der die native Karte umschließt
Der Holder besitzt zwei Elemente: die Plattform-Ansicht und die Karteninstanz. SDK-spezifischer Code wird ab hier isoliert und nicht an den gemeinsamen Code durchgelassen.
Umrechnung zwischen Koordinaten und Bildschirmposition
Geografische Koordinaten und Pixelpositionen auf dem Bildschirm können gegenseitig umgerechnet werden. Dies wird verwendet, wenn eine benutzerdefinierte UI über die Karte gelegt wird.
// Nur herausholen, wenn Sie die native API wirklich brauchen 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 / ...
Code, der den Holder verwendet, hängt vom Anbieter ab. Bitte trennen Sie bewusst die Teile, die Sie gemeinschaftlich halten möchten, von den Teilen, für die Sie gezielt eine spezifische API verwenden.