Google Map
Add a Marker
A map by itself is useful for exploring, but what if you want to tell the user where something is?
That's where markers come in, and where the GoogleMap
content parameter becomes useful.
Our GoogleMap
call is going to get more complex over the next several steps. By
Creating a new @Composable to hold the map, we can set up parameters
show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...
import com.google.maps.android.compose.rememberMarkerState
@Composable
fun GoogleMapDisplay(
place: LatLng,
placeDescription: String,
modifier: Modifier,
) {
val placeState =
rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
modifier = modifier,
) {
MarkerInfoWindowContent(
state = placeState,
title = placeDescription,
onClick = {
placeState.showInfoWindow()
true
}
)
}
}
and Simplify the Caller (passing in a place)
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 ->
// GoogleMap(
val googleHQ = LatLng(37.42423291057923, -122.08811454627153)
GoogleMapDisplay(
place = googleHQ,
placeDescription = "Google HQ",
modifier = Modifier.padding(innerPadding).fillMaxSize(),
// ) {
// // no content yet
// }
)
}
}
}
}
}
Our new @Composable takes a LatLng
for the place to display the marker, a String
description
of the marker, and a Modifier
. It's a great habit to pass Modifiers
into your Composable
functions; this allows the caller more control over how the called Composable is placed. You'll
want to Pass the Modifier}} to the top-level Composable that your function calls, or use it as a
base modifier (rather than passing Modifier.xxx()
, you'll pass modifier.xxx()
to start with
the passed-in Modifier
).
show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...
@Composable
fun GoogleMapDisplay(
// ...
) {
// ...
GoogleMap(
modifier = modifier,
) {
MarkerInfoWindowContent(
// ...
}
}
Now for the marker. We need to set up the data for the Marker - we use rememberMarkerState to
create and remember
a MarkerState
instance. This instance will be re-created whenever the
key
passed to it is changed. In this example, we want to change the position whenever the
LatLng
changes. rememberMarkerState
takes a String
as a key, so we just convert the
LatLng
to a String
.
Once we have data, we can Create the Marker in the GoogleMap
content.
show in full file app/src/main/java/com/androidbyexample/compose/google/google/maps/GoogleMapDisplay.kt
// ...
@Composable
fun GoogleMapDisplay(
// ...
modifier: Modifier,
) {
val placeState =
rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
modifier = modifier,
) {
MarkerInfoWindowContent(
state = placeState,
title = placeDescription,
onClick = {
placeState.showInfoWindow()
true
}
)
}
}
Running the application is a bit disappointing; we're still centered at 0.0, 0.0. If we pan over we'll see the marker:
You can zoom by double-tapping, pinching, or tapping the "+" button to see
If you tap on the marker, its description is displayed and the map centers on the marker:
All code changes
ADDED: 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.GoogleMap
import com.google.maps.android.compose.MarkerInfoWindowContent
import com.google.maps.android.compose.rememberMarkerState
@Composable
fun GoogleMapDisplay(
place: LatLng,
placeDescription: String,
modifier: Modifier,
) {
val placeState =
rememberMarkerState(key = place.toString(), position = place)
GoogleMap(
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.LatLng
import com.google.maps.android.compose.GoogleMap
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
GoogleMapsTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
// GoogleMap(
val googleHQ = LatLng(37.42423291057923, -122.08811454627153)
GoogleMapDisplay(
place = googleHQ,
placeDescription = "Google HQ",
modifier = Modifier.padding(innerPadding).fillMaxSize(),
// ) {
// // no content yet
// }
)
}
}
}
}
}