MarkerComposable throw Fatal Exception: java.lang.IllegalArgumentException: width and height must be > 0
When I try to make a cluter of custom markers with MarkerComposable it gives me an error of size 0 even if I forze a size (I have tried every modifier of size= size, height/width, requiredSize,..) . If I don't user Clusters, it works. There's a few reports of this exact same problem that you have closed even tough people are still telling it is still happening so please don't close this until everyone says it's fixed
Environment details
- I am using the API mapsCompose = "6.5.0"
- Windows with Android Studio: Build #AI-243.22562.218.2431.13114758, built on February 25, 2025
Runtime version: 21.0.5+-12932927-b750.29 amd64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Kotlin plugin: K2 mode
Steps to reproduce
- Try to make a cluter of markers
Code example
`package es.platorama.ui.explorador.mapa
import android.graphics.Bitmap import android.util.Log import android.view.View import android.view.ViewGroup import android.widget.FrameLayout import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.DarkMode import androidx.compose.material.icons.filled.WbSunny import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Path import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.graphics.createBitmap import com.google.android.gms.maps.CameraUpdateFactory import com.google.android.gms.maps.model.BitmapDescriptorFactory import com.google.android.gms.maps.model.CameraPosition import com.google.android.gms.maps.model.LatLng import com.google.android.gms.maps.model.MapStyleOptions import com.google.maps.android.clustering.ClusterItem import com.google.maps.android.compose.GoogleMap import com.google.maps.android.compose.GoogleMapComposable import com.google.maps.android.compose.MapProperties import com.google.maps.android.compose.MapUiSettings import com.google.maps.android.compose.MapsComposeExperimentalApi import com.google.maps.android.compose.MarkerComposable import com.google.maps.android.compose.MarkerState import com.google.maps.android.compose.clustering.Clustering import com.google.maps.android.compose.rememberCameraPositionState import es.platorama.R import es.platorama.ui.explorador.BotonCentrarMapaCustom import es.platorama.ui.explorador.MarcadorLocal
@OptIn(MapsComposeExperimentalApi::class) @Composable fun MapScreen(ubiUser: LatLng?, marcadores: State<List<MarcadorLocal>>, bottomPadding: Dp) { var initialCameraSet by remember { mutableStateOf(false) } val defaultPosition = LatLng(0.0, 0.0) var isDarkMode by remember { mutableStateOf(true) } // Estado para cambiar el tema del mapa val context = LocalContext.current
val cameraPositionState = rememberCameraPositionState {
position = CameraPosition.fromLatLngZoom(ubiUser ?: defaultPosition, 15f)
}
LaunchedEffect(ubiUser) {
if (!initialCameraSet && ubiUser != null) {
cameraPositionState.animate(CameraUpdateFactory.newLatLng(ubiUser))
initialCameraSet = true
}
}
val mapProperties = remember(isDarkMode) {
MapProperties(
isMyLocationEnabled = true,
mapStyleOptions = if (isDarkMode) {
MapStyleOptions.loadRawResourceStyle(context, R.raw.map_style_dark)
} else {
null // Usa el tema predeterminado de Google Maps
}
)
}
val mapUiSettings = MapUiSettings(
myLocationButtonEnabled = false,
zoomControlsEnabled = false,
compassEnabled = false,
)
Box(modifier = Modifier.fillMaxSize()) {
GoogleMap(
modifier = Modifier.fillMaxSize(),
cameraPositionState = cameraPositionState,
properties = mapProperties,
uiSettings = mapUiSettings,
contentPadding = PaddingValues(bottom = bottomPadding)
) {
val marcadoresItems =
marcadores.value.map { marcador ->
MarcadorCustomClusterItem(
position = marcador.latLng,
title = "fdasfadsfa",
snippet = marcador.rating.toString()
)
}
Log.d("Carlos MapScreen", "Llamando a clustering-> ${marcadoresItems.size}")
Clustering(
items = marcadoresItems,
clusterItemContent = {
Log.d("Carlos MapScreen", "ClusterItemContent called")
CustomMapMarker(
latLng = it.position,
rating = it.snippet.toFloat()
)
}
)
/*
// Marcadores personalizados
marcadores.value.forEach() { marcador ->
CustomMapMarker(marcador.latLng, marcador.rating,)
}*/
}
// Botón para cambiar el modo claro/oscuro
FloatingActionButton(
onClick = { isDarkMode = !isDarkMode },
modifier = Modifier
.align(Alignment.TopStart)
.padding(15.dp)
.size(30.dp)
) {
Icon(
imageVector = if (isDarkMode) Icons.Default.DarkMode else Icons.Default.WbSunny,
contentDescription = "Cambiar tema del mapa"
)
}
// Botón para centrar en user (Sustituyo al que viene por defecto)
BotonCentrarMapaCustom(cameraPositionState, ubiUser, defaultPosition,
modifier = Modifier
.align(Alignment.TopEnd)
.padding(15.dp)
.size(30.dp)
)
}
}
// Define una clase para tus items de cluster class MarcadorCustomClusterItem( private val position: LatLng, private val title: String, private val snippet: String ) : ClusterItem { override fun getPosition(): LatLng = position override fun getTitle(): String = title override fun getSnippet(): String = snippet override fun getZIndex(): Float = 1f }
@Composable @GoogleMapComposable fun CustomMapMarker(latLng: LatLng ,rating: Float) { val markerState = remember { MarkerState(position = latLng) } Log.d("Carlos MapScreen", "CustomMapMarker called inside") MarkerComposable ( keys = arrayOf("array test"), state = markerState, ){ Box( modifier = Modifier .requiredSize(50.dp) ) { Column( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.fillMaxSize() ) { Box( modifier = Modifier .background(Color(0xFF6200EE), shape = RoundedCornerShape(4.dp)) .padding(horizontal = 8.dp, vertical = 4.dp) ) { Text( //text = String.format("%.1f", rating), text = "prueba", color = Color.White, fontSize = 14.sp, fontWeight = FontWeight.Bold ) }
Spacer(modifier = Modifier.height(2.dp)) // Añade un espacio para asegurar altura
Canvas(
modifier = Modifier
.size(width = 20.dp, height = 10.dp)
.align(Alignment.CenterHorizontally)
) {
val path = Path().apply {
moveTo(0f, 0f)
lineTo(size.width, 0f)
lineTo(size.width / 2f, size.height)
close()
}
drawPath(
path = path,
color = Color(0xFF6200EE)
)
}
}
}
}
}
/* @Preview @Composable fun preview(){ CustomMapMarker(rating = 4.5f) }*/`
Stack trace
java.lang.IllegalStateException: The ComposeView was measured to have a width or height of zero. Make sure that the content has a non-zero size. at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:58) at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.access$renderComposableToBitmapDescriptor(RememberComposeBitmapDescriptor.kt:1) at com.google.maps.android.compose.RememberComposeBitmapDescriptorKt.rememberComposeBitmapDescriptor(RememberComposeBitmapDescriptor.kt:29) at com.google.maps.android.compose.MarkerKt.MarkerComposable-Khg_OnI(Marker.kt:342) at es.platorama.ui.explorador.mapa.MapaScreensKt.CustomMapMarker(MapaScreens.kt:169) at es.platorama.ui.explorador.mapa.ComposableSingletons$MapaScreensKt$lambda-1$1.invoke(MapaScreens.kt:116) at es.platorama.ui.explorador.mapa.ComposableSingletons$MapaScreensKt$lambda-1$1.invoke(MapaScreens.kt:114) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:118) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95) at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$createAndAddView$view$2.invoke(ClusterRenderer.kt:95) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer$InvalidatingComposeView.Content(ClusterRenderer.kt:222) at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:259) at androidx.compose.ui.platform.AbstractComposeView$ensureCompositionCreated$1.invoke(ComposeView.android.kt:258) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380) at androidx.compose.ui.platform.CompositionLocalsKt.ProvideCommonCompositionLocals(CompositionLocals.kt:216) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:132) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$ProvideAndroidCompositionLocals$3.invoke(AndroidCompositionLocals.android.kt:131) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:380) at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.ProvideAndroidCompositionLocals(AndroidCompositionLocals.android.kt:121) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:155) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1$3.invoke(Wrapper.android.kt:154) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:401) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:154) at androidx.compose.ui.platform.WrappedComposition$setContent$1$1.invoke(Wrapper.android.kt:133) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:109) at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:35) 2025-03-17 19:23:04.541 23672-23672 AndroidRuntime es.platorama.debug E at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:97) (Ask Gemini) at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:3595) at androidx.compose.runtime.ComposerImpl.composeContent$runtime_release(Composer.kt:3522) at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:743) at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1122) at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3876) at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:649) at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:635) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:133) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124) at androidx.compose.ui.platform.AndroidComposeView.setOnViewTreeOwnersAvailable(AndroidComposeView.android.kt:1626) at androidx.compose.ui.platform.WrappedComposition.setContent(Wrapper.android.kt:124) at androidx.compose.ui.platform.WrappedComposition.onStateChanged(Wrapper.android.kt:180) at androidx.lifecycle.LifecycleRegistry$ObserverWithState.dispatchEvent(LifecycleRegistry.jvm.kt:320) at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.jvm.kt:198) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:131) at androidx.compose.ui.platform.WrappedComposition$setContent$1.invoke(Wrapper.android.kt:124) at androidx.compose.ui.platform.AndroidComposeView.onAttachedToWindow(AndroidComposeView.android.kt:1707) at android.view.View.dispatchAttachedToWindow(View.java:22895) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3506) at android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.java:3513) at android.view.ViewGroup.addViewInner(ViewGroup.java:5318) at android.view.ViewGroup.addView(ViewGroup.java:5104) at android.view.ViewGroup.addView(ViewGroup.java:5044) at android.view.ViewGroup.addView(ViewGroup.java:5016) at com.google.maps.android.compose.MapComposeViewRenderKt.startRenderingComposeView(MapComposeViewRender.kt:46) at com.google.maps.android.compose.MapViewDelegate.startRenderingComposeView(GoogleMap.kt:378) at com.google.maps.android.compose.MapComposeViewRenderKt$rememberComposeUiViewRenderer$1$1.startRenderingView(MapComposeViewRender.kt:92) at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.createAndAddView(ClusterRenderer.kt:99) at com.google.maps.android.compose.clustering.ComposeUiClusterRenderer.onClustersChanged(ClusterRenderer.kt:67) at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:322) at com.google.maps.android.clustering.ClusterManager$ClusterTask.onPostExecute(ClusterManager.java:308) at android.os.AsyncTask.finish(AsyncTask.java:771) at android.os.AsyncTask.-$$Nest$mfinish(Unknown Source:0) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:788) at android.os.Handler.dispatchMessage(Handler.java:109) at android.os.Looper.loopOnce(Looper.java:232) at android.os.Looper.loop(Looper.java:317) at android.app.ActivityThread.main(ActivityThread.java:8787) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:591) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:871)
+1
for the record:
more discussion in #641