Estoy tratando de usar ExposedDropdownMenuBox de Jetpack Compose, pero no puedo evitar que muestre el menú cuando me desplazo.
Por ejemplo, aquí está el código para replicar este problema:
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { MyApplicationTheme { Surface(color = MaterialTheme.colors.background) { Column( modifier = Modifier .padding(horizontal = 8.dp) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(8.dp) ) { repeat(20){ ExposedDropdownMenuSample() } } } } } } }ExposedDropdownMenuSample se tomó de las muestras oficiales.
Este es un GIF que muestra el problema.
¿Cómo puedo evitar que esto suceda?
Este código usa la versión de composición 1.1.0-rc01 .
Pude arreglar esto con este feo truco:
private fun Modifier.cancelOnExpandedChangeIfScrolling() = pointerInput(Unit) { forEachGesture { coroutineScope { awaitPointerEventScope { var event: PointerEvent var startPosition = Offset.Unspecified var cancel = false do { event = awaitPointerEvent(PointerEventPass.Initial) if (startPosition == Offset.Unspecified) { startPosition = event.changes.first().position } val distance = startPosition.minus(event.changes.last().position).getDistance() cancel = distance > 10f || cancel } while ( !event.changes.all { it.changedToUp() } ) if (cancel) { event.changes.forEach { it.consumeAllChanges() } } } } } } luego agréguelo a ExposedDropdownMenuBox como:
ExposedDropdownMenuBox( expanded = expanded, onExpandedChange = { expanded = !expanded }, modifier = Modifier.cancelOnExpandedChangeIfScrolling() ) Entonces, ¿básicamente verifica si hubo un arrastre de más de 10 píxeles? y si es verdadero, consume los eventos para que no active onExpandedChange .
10 es solo un número mágico que funcionó bien para mis pruebas, pero parece demasiado bajo para un dispositivo de pantalla de alta resolución. Estoy seguro de que hay una mejor manera de calcular este número... ¿Tal vez alguien con más experiencia pueda ayudar con esto hasta que tengamos una solución adecuada?
Encontré una solución un poco menos hacky:
Obtiene la información de si hay un desplazamiento en curso desde el estado de desplazamiento de la columna.
val scrollState = rememberScrollState() val isScrolling = scrollState.isScrollInProgress Column( modifier = Modifier .padding(horizontal = 8.dp) .verticalScroll(scrollState), ... ) ...En ExposedDropdownMenuBox , puede cambiar el oyente a
onExpandedChange = { expanded = !expanded && !isScrolling },=> El menú desplegable nunca se abre mientras se desplaza. También se cierra automáticamente tan pronto como comienza a desplazarse por la columna principal. Sin embargo, es posible desplazarse dentro del menú desplegable. Por supuesto, también puedes cambiarlo a algo como
expanded = if (isScrolling) expanded else !expandedPara dejar todo como está mientras se desplaza