DEV Community

myougaTheAxo
myougaTheAxo

Posted on

Google Maps + Jetpack Compose: Maps, Markers & Location Guide

Google Maps + Jetpack Compose: Maps, Markers & Location Guide

Google Maps integration in Jetpack Compose is handled through the maps-compose library, providing composable functions for map rendering, markers, and location drawing.

Google Map Composable

The GoogleMap composable is the foundation:

@Composable
fun MyMapScreen() {
    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(
            LatLng(37.7749, -122.4194), // San Francisco
            12f
        )
    }

    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState,
        properties = MapProperties(
            isMyLocationEnabled = true,
            mapType = MapType.NORMAL
        )
    )
}
Enter fullscreen mode Exit fullscreen mode

Adding Markers

Use Marker or MarkerComposable for location pins:

GoogleMap(
    modifier = Modifier.fillMaxSize(),
    cameraPositionState = cameraPositionState
) {
    Marker(
        state = MarkerState(position = LatLng(37.7749, -122.4194)),
        title = "San Francisco",
        snippet = "California"
    )

    MarkerComposable(
        state = MarkerState(position = LatLng(34.0522, -118.2437)),
        onClick = { true }
    ) {
        Icon(
            painter = painterResource(id = R.drawable.ic_location),
            contentDescription = "Location",
            tint = Color.Red,
            modifier = Modifier.size(32.dp)
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Camera State Management

Manage zoom, pan, and animation:

val cameraPositionState = rememberCameraPositionState()

Button(
    onClick = {
        cameraPositionState.move(
            CameraUpdateFactory.newLatLngZoom(
                LatLng(34.0522, -118.2437),
                15f
            )
        )
    }
) {
    Text("Go to LA")
}

// Listen to camera changes
LaunchedEffect(cameraPositionState.isMoving) {
    if (!cameraPositionState.isMoving) {
        val zoomLevel = cameraPositionState.position.zoom
        println("User zoomed to level: $zoomLevel")
    }
}
Enter fullscreen mode Exit fullscreen mode

Current Location with FusedLocationProviderClient

Get user location:

val context = LocalContext.current
val locationClient = remember {
    LocationServices.getFusedLocationProviderClient(context)
}

LaunchedEffect(Unit) {
    if (ActivityCompat.checkSelfPermission(
        context,
        Manifest.permission.ACCESS_FINE_LOCATION
    ) == PackageManager.PERMISSION_GRANTED
    ) {
        locationClient.lastLocation.addOnSuccessListener { location ->
            if (location != null) {
                val cameraUpdate = CameraUpdateFactory.newLatLngZoom(
                    LatLng(location.latitude, location.longitude),
                    13f
                )
                cameraPositionState.move(cameraUpdate)
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Drawing Polylines & Circles

Add geographic shapes:

GoogleMap(
    cameraPositionState = cameraPositionState
) {
    // Polyline (route)
    Polyline(
        points = listOf(
            LatLng(37.7749, -122.4194),
            LatLng(37.7849, -122.4094),
            LatLng(37.7949, -122.3994)
        ),
        color = Color.Blue,
        width = 5f
    )

    // Circle (radius zone)
    Circle(
        center = LatLng(37.7749, -122.4194),
        radius = 500.0, // meters
        fillColor = Color(0x33FF0000),
        strokeColor = Color.Red,
        strokeWidth = 2f
    )
}
Enter fullscreen mode Exit fullscreen mode

MapProperties Configuration

Customize map behavior and appearance:

GoogleMap(
    properties = MapProperties(
        isMyLocationEnabled = true,
        mapType = MapType.SATELLITE,
        isIndoorEnabled = true,
        isTrafficEnabled = true,
        isBuildingsEnabled = true,
        minZoomPreference = 5f,
        maxZoomPreference = 20f
    ),
    uiSettings = MapUiSettings(
        zoomControlsEnabled = true,
        compassEnabled = true,
        myLocationButtonEnabled = true,
        scrollGesturesEnabled = true,
        zoomGesturesEnabled = true
    )
)
Enter fullscreen mode Exit fullscreen mode

Responding to Map Clicks

Handle user interactions:

var selectedLocation by remember { mutableStateOf<LatLng?>(null) }

GoogleMap(
    onMapClick = { latLng ->
        selectedLocation = latLng
    },
    cameraPositionState = cameraPositionState
) {
    selectedLocation?.let {
        Marker(
            state = MarkerState(position = it),
            title = "Selected",
            snippet = "${it.latitude}, ${it.longitude}"
        )
    }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Request Permissions - Always check ACCESS_FINE_LOCATION at runtime
  2. API Key - Store in AndroidManifest.xml or secure config
  3. Memory Management - Clean up location clients in onCleared()
  4. Camera Animation - Use newLatLngZoom() for smooth transitions
  5. Marker Clustering - For 100+ markers, use MarkerClusterer
  6. Offline Support - Consider caching tile data for areas
  7. Testing - Use Compose preview with mock MapComposable

Google Maps in Compose provides powerful location-based features while maintaining Jetpack Compose's declarative paradigm.


8 Android App Templates → https://myougatheax.gumroad.com

Top comments (0)