androidgoogle-mapsandroid-jetpack-composegoogle-maps-api-2

Pointing the camera at the coordinates


I will point the camera to the coordinates according to the existing API. but only the marker can go to the coordinates but not the camera.

Please help

I include my code snippet

// Membuat objek LatLng dari nilai latitude dan longitude
    val coordinatesStr = gempaInfo?.infogempa?.gempa?.coordinates
    val (latitudeStr, longitudeStr) = coordinatesStr?.split(",") ?: listOf("0.0", "0.0")
    val latitude = latitudeStr.trim().toDoubleOrNull() ?: 0.0
    val longitude = longitudeStr.trim().toDoubleOrNull() ?: 0.0
    val koordinat = LatLng(latitude, longitude)

    val cameraPositionState = rememberCameraPositionState {
        position = CameraPosition.fromLatLngZoom(koordinat, 10f)
    }

    // Menampilkan peta Google dengan marker di koordinat
    GoogleMap(
        modifier = Modifier.fillMaxSize(),
        cameraPositionState = cameraPositionState
    ) {
        Marker(
            state = MarkerState(position = koordinat),
            title = "Lokasi Gempa",
            snippet = "Marker di lokasi gempa"
        )
    }

I want when the map is loaded it will automatically point to the coordinates according to what has been created by the API


Solution

  • Does val coordinatesStr = gempaInfo?.infogempa?.gempa?.coordinates ever change? If gempaInfo is static, your code should work. If it changes, you will have to observe gempInfo and update the cameraPositionState.

    For example

    val scope = rememberCoroutineScope()
    LaunchedEffect(gempaInfo) {
    
    val koordinat = gempaInfo?.infogempa?.gempa?.coordinates
      ?.split(",")
      ?.map { it.trim().toDoubleOrNull() ?: 0.0 }
      ?.let { coords -> LatLng(coords[0], coords[1]) } ?: LatLng(0.0. 0.0)
       
      scope.launch {
            cameraPositionState.animate(
                update = CameraUpdateFactory.newLatLngBounds(boundingBox, 64),
                durationMs = 1000
            )
        }
    }
    

    Here is a longer example that makes use of Kotlin flows to jump around. Notice that the data is cleaned up before getting to the GoogleMap. (In general, apps should only send cleaned up data to the UI.)

    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            enableEdgeToEdge()
            setContent {
                val locationStrings = listOf(
                    null,
                    "39.9559152,-105.2938497",
                    "39.429725,-105.080054",
                    "39.9559152",
                    "null,no op",
                    " 38.839155 , -105.0345258 ",
                )
    
                val locFlow = MutableStateFlow(LatLng(0.0, 0.0))
    
                val context = LocalContext.current
    
                LaunchedEffect(Unit) {
                    while (true) {
                        locationStrings.asFlow()
                            .onEach {
                                delay(5.seconds)
                                Log.w("LocationFollower", "Location: $it")
                            }
                            .mapNotNull { locationString ->
                                locationString?.split(",")
                                    ?.mapNotNull { it.trim().toDoubleOrNull() }
                                    ?.takeIf { it.size == 2 }
                                    ?.let { (lat, lng) ->
                                        LatLng(lat, lng)
                                    } ?: run {
                                        Log.w("LocationFollower", "Invalid location: $locationString")
                                        Toast.makeText(
                                            context,
                                            "Invalid location: $locationString",
                                            Toast.LENGTH_SHORT
                                        ).show()
                                        null
                                    }
                            }.collect {
                                locFlow.value = it
                            }
                    }
                }
    
                LocationFollowerTheme {
                    Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                        val location by locFlow.collectAsState(initial = LatLng(0.0, 0.0))
                        MyMap(modifier = Modifier.padding(innerPadding), location = location)
                    }
                }
            }
        }
    }
    
    @Composable
    fun MyMap(modifier: Modifier, location: LatLng) {
        val cameraPositionState = rememberCameraPositionState {
            position = CameraPosition.fromLatLngZoom(location, 15f)
        }
    
        val scope = rememberCoroutineScope()
    
        val markerState = rememberMarkerState(position = location)
    
        LaunchedEffect(location) {
            scope.launch {
                cameraPositionState.animate(
                    CameraUpdateFactory.newCameraPosition(
                        CameraPosition.fromLatLngZoom(location, 15f)
                    ),
                    2.seconds.inWholeMilliseconds.toInt()
                )
            }
    
            markerState.position = location
        }
    
        GoogleMap(
            modifier = modifier,
            cameraPositionState = cameraPositionState
        ) {
            Marker(
                state = markerState,
                title = "Marker",
            )
        }
    }