Skip to content

Circle

Los círculos son superposiciones circulares que se pueden dibujar en el mapa con propiedades de radio, trazo y relleno personalizables. Son útiles para representar áreas, rangos o zonas.

Cuando tienes pocos círculo, especificar opciones directamente es más fácil. Especificar id puede reducir Recomposiciones innecesarias.

@Composable
fun MapViewScope.Circle(
center: GeoPointInterface,
radiusMeters: Double,
geodesic: Boolean = false,
strokeColor: Color = Color.Red,
strokeWidth: Dp = 2.dp,
fillColor: Color = Color.White.copy(alpha = 0.5f),
extra: Serializable? = null,
id: String? = null
)
  • center: Punto geográfico central del círculo (GeoPointInterface)
  • radiusMeters: Radio en metros (Double)
  • geodesic: Si se debe dibujar el círculo usando bordes geodésicos que sigan la curvatura de la Tierra (predeterminado: false)
  • strokeColor: Color del borde del círculo (predeterminado: Color.Red)
  • strokeWidth: Ancho de la línea del borde (predeterminado: 2.dp)
  • fillColor: Color de relleno del interior del círculo (predeterminado: blanco semi-transparente)
  • extra: Datos adicionales adjuntos al círculo (Serializable?)
  • id: Identificador único para el círculo (String?)
// Reemplace MapView con su proveedor de mapas elegido, como GoogleMapView, MapboxMapView
MapView(state = mapViewState) {
Circle(
center = GeoPoint.fromLatLong(37.7749, -122.4194),
radiusMeters = 1000.0, // 1km radius
strokeColor = Color.Blue,
fillColor = Color.Blue.copy(alpha = 0.3f),
id = "downtown-area"
)
}

Según el patrón de la aplicación de ejemplo, aquí se muestra cómo crear un círculo interactivo con marcadores arrastrables:

@Composable
fun InteractiveCircleExample() {
var centerPosition by remember {
mutableStateOf(GeoPoint.fromLatLong(37.7749, -122.4194))
}
var radiusMeters by remember { mutableStateOf(1000.0) }
// Calculate edge marker position
val edgePosition = remember(centerPosition, radiusMeters) {
// Calculate a point that's 'radiusMeters' meters away from center
// Esto está simplificado - el cálculo real consideraría la curvatura de la Tierra
val latOffset = radiusMeters / 111000.0 // Rough meters per degree latitude
GeoPoint.fromLatLong(
centerPosition.latitude + latOffset,
centerPosition.longitude
)
}
val circleState = CircleState(
center = centerPosition,
radiusMeters = radiusMeters,
strokeColor = Color.Blue,
fillColor = Color.Blue.copy(alpha = 0.3f),
clickable = true,
onClick = { circleEvent ->
println("Circle clicked at: ${circleEvent.clicked}")
}
)
val centerMarker = MarkerState(
position = centerPosition,
icon = DefaultIcon(
fillColor = Color.Blue,
label = "C"
),
draggable = false
)
val edgeMarker = MarkerState(
position = edgePosition,
icon = DefaultIcon(
fillColor = Color.Green,
label = "E"
),
draggable = true,
onDrag = { markerState ->
// Calculate new radius based on edge marker position
val distance = calculateDistance(centerPosition, markerState.position)
radiusMeters = distance
}
)
// Reemplace MapView con su proveedor de mapas elegido, como GoogleMapView, MapboxMapView
MapView(
state = mapViewState
) {
Circle(circleState)
Marker(centerMarker)
Marker(edgeMarker)
}
}
@Composable
fun DynamicCircleExample() {
var circleRadius by remember { mutableStateOf(500.0) }
var circleColor by remember { mutableStateOf(Color.Blue) }
Column {
// Controls
Slider(
value = circleRadius.toFloat(),
onValueChange = { circleRadius = it.toDouble() },
valueRange = 100f..2000f,
modifier = Modifier.padding(16.dp)
)
Row {
Button(onClick = { circleColor = Color.Red }) {
Text("Red")
}
Button(onClick = { circleColor = Color.Blue }) {
Text("Blue")
}
Button(onClick = { circleColor = Color.Green }) {
Text("Green")
}
}
// Map with dynamic circle
// Reemplace MapView con su proveedor de mapas elegido, como GoogleMapView, MapboxMapView
MapView(state = mapViewState) {
Circle(
center = GeoPoint.fromLatLong(37.7749, -122.4194),
radiusMeters = circleRadius,
strokeColor = circleColor,
fillColor = circleColor.copy(alpha = 0.3f)
)
// Center marker
Marker(
position = GeoPoint.fromLatLong(37.7749, -122.4194),
icon = DefaultIcon(
fillColor = circleColor,
label = "${circleRadius.toInt()}m"
)
)
}
}
}

Las interacciones de círculo se manejan con su componente de proveedor de mapas:

// Reemplace MapView con su proveedor de mapas elegido, como GoogleMapView, MapboxMapView
MapView(
state = mapViewState
) {
Circle(
center = GeoPoint.fromLatLong(37.7749, -122.4194),
radiusMeters = 1000.0,
clickable = true,
extra = "Clickable circle",
onClick = { circleEvent ->
val circle = circleEvent.state
val clickPoint = circleEvent.clicked
println("Circle clicked:")
println(" Center: ${circle.center}")
println(" Radius: ${circle.radiusMeters}m")
println(" Click point: ${clickPoint}")
println(" Extra data: ${circle.extra}")
}
)
}
// Thin border
Circle(
center = center,
radiusMeters = 500.0,
strokeColor = Color.Black,
strokeWidth = 1.dp
)
// Thick border
Circle(
center = center,
radiusMeters = 500.0,
strokeColor = Color.Black,
strokeWidth = 5.dp
)
// No border
Circle(
center = center,
radiusMeters = 500.0,
strokeColor = Color.Transparent,
strokeWidth = 0.dp
)
// Solid fill
Circle(
center = center,
radiusMeters = 500.0,
fillColor = Color.Red
)
// Semi-transparent fill
Circle(
center = center,
radiusMeters = 500.0,
fillColor = Color.Red.copy(alpha = 0.5f)
)
// No fill
Circle(
center = center,
radiusMeters = 500.0,
fillColor = Color.Transparent
)

La propiedad id proporciona un identificador único para círculos, permitiendo un seguimiento y gestión eficientes:

@Composable
fun CircleIdentificationExample() {
val mapViewState = rememberGoogleMapViewState()
// Use ID in event handling
val onCircleClick: OnCircleEventHandler = { circleEvent ->
when (circleEvent.state.id) {
"zone-a" -> handleZoneA()
"zone-b" -> handleZoneB()
else -> handleUnknownZone()
}
}
// Create circles with unique IDs
val circles = listOf(
CircleState(
center = GeoPoint.fromLatLong(37.7749, -122.4194),
radiusMeters = 1000.0,
strokeColor = Color.Red,
fillColor = Color.Red.copy(alpha = 0.3f),
id = "zone-a",
onClick = onCircleClick
),
CircleState(
center = GeoPoint.fromLatLong(37.7849, -122.4094),
radiusMeters = 1500.0,
strokeColor = Color.Blue,
fillColor = Color.Blue.copy(alpha = 0.3f),
id = "zone-b",
onClick = onCircleClick
)
)
MapView(
state = mapViewState
) {
circles.forEach { circle -> Circle(circle) }
}
}
private fun handleZoneA() {
println("Zone A clicked")
}
private fun handleZoneB() {
println("Zone B clicked")
}
private fun handleUnknownZone() {
println("Unknown zone clicked")
}
  • Identificación Única: Distinguir entre círculos incluso cuando tienen propiedades similares
  • Manejo de Eventos: Simplifica el manejo de eventos de clic y la lógica específica de área
  • Gestión del Estado: Permite actualizaciones eficientes y gestión de selección
  • Rendimiento: Facilita la renderización y actualizaciones optimizadas

Ejemplo detallado de manejo de eventos de clic de círculo:

@Composable
fun CircleClickEventExample() {
val mapViewState = rememberGoogleMapViewState()
// Replace MapView with your chosen map provider, such as GoogleMapView, MapboxMapView
MapView(
state = mapViewState
) {
Circle(
center = GeoPoint.fromLatLong(37.7749, -122.4194),
radiusMeters = 1000.0,
clickable = true,
extra = "Clickable circle",
onClick = { circleEvent ->
val circle = circleEvent.state
val clickPoint = circleEvent.clicked
println("Circle clicked:")
println(" Center: ${circle.center}")
println(" Radius: ${circle.radiusMeters}m")
println(" Click point: ${clickPoint}")
println(" Extra data: ${circle.extra}")
}
)
}
}
  1. Use Radio Apropiado: Considere el nivel de zoom del mapa al establecer el radio del círculo
  2. Proporcione IDs Únicos: Siempre establezca valores id únicos al trabajar con múltiples círculos
  3. Contraste de Color: Asegure que los colores de trazo y relleno proporcionen buena visibilidad en el mapa
  4. Rendimiento: Evite crear demasiados círculos grandes ya que pueden impactar el rendimiento de renderización
  5. Retroalimentación Interactiva: Proporcione retroalimentación visual cuando los círculos sean clickeables
  6. Estilo Consistente: Mantenga un estilo de círculo consistente en su aplicación
  7. Datos Adicionales: Utilice el parámetro extra para almacenar metadatos para manejo de eventos
  8. Gestión de Z-Index: Considere el orden de dibujo cuando los círculos se superponen