Google Map
Initial Position
Let's make the app more friendly by automatically moving to that marker position.
First, we define a CameraPosition
to indicate where we want to jump to on the map. Think of this
as a literal camera, pointing to a LatLng from a specific bearing and tilt, zoomed in/out to a
certain factor.
We define a CameraPositionState
similar to our MarkerState
to hold the data for the map camera.
It's position is initialized to our defaultCameraPosition
, but as the user interacts with the map
(panning, zooming, rotating, etc) this state will be updated.
show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
// ...
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
setContent {
GoogleMapsTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
val googleHQ = LatLng(37.42423291057923, -122.08811454627153)
val defaultCameraPosition = CameraPosition.fromLatLngZoom(googleHQ, 11f)
val cameraPositionState = rememberCameraPositionState {
position = defaultCameraPosition
}
GoogleMapDisplay(
place = googleHQ,
placeDescription = "Google HQ",
cameraPositionState = cameraPositionState,
modifier = Modifier.padding(innerPadding).fillMaxSize(),
)
}
}
}
}
}
Where should we define these state? Only as high in the call hierarchy as needed. Pretend that we
have a ViewModel
that needs to know when the camera moves; defining the cameraPositionState
in
onCreate
as we're doing here gives us access to that state. If instead we defined it inside
GoogleMapView
, we would only have access to that state inside GoogleMapView
(unless we passed
an onCameraChange
function that could be used to send out changed camera values).
Pulling state up out of functions like this is called "State Hoisting".
We use that state inside the GoogleMap
call
show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...
@Composable
fun GoogleMapDisplay(
place: LatLng,
placeDescription: String,
cameraPositionState: CameraPositionState,
modifier: Modifier,
) {
val placeState =
rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
cameraPositionState = cameraPositionState,
modifier = modifier,
) {
// ...
}
}
Now when we run the application, we see the map centered on Google HQ.
All code changes
CHANGED: app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
package com.androidbyexample.compose.google.google.maps
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.CameraPositionState
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.MarkerInfoWindowContent
import com.google.maps.android.compose.rememberMarkerState
@Composable
fun GoogleMapDisplay(
place: LatLng,
placeDescription: String,
cameraPositionState: CameraPositionState,
modifier: Modifier,
) {
val placeState =
rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
cameraPositionState = cameraPositionState,
modifier = modifier,
) {
MarkerInfoWindowContent(
state = placeState,
title = placeDescription,
onClick = {
placeState.showInfoWindow()
true
}
)
}
}
CHANGED: app/src/main/java/com/androidbyexample/compose/google/google/maps/MainActivity.kt
package com.androidbyexample.compose.google.google.maps
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.androidbyexample.compose.google.google.maps.ui.theme.GoogleMapsTheme
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.GoogleMap
import com.google.maps.android.compose.rememberCameraPositionState
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
GoogleMapsTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
val googleHQ = LatLng(37.42423291057923, -122.08811454627153)
val defaultCameraPosition = CameraPosition.fromLatLngZoom(googleHQ, 11f)
val cameraPositionState = rememberCameraPositionState {
position = defaultCameraPosition
}
GoogleMapDisplay(
place = googleHQ,
placeDescription = "Google HQ",
cameraPositionState = cameraPositionState,
modifier = Modifier.padding(innerPadding).fillMaxSize(),
)
}
}
}
}
}