Seguimiento de visibilidad en Compose

Hacer un seguimiento de cuándo un elemento de la IU está visible en la pantalla es útil para una variedad de casos de uso, como el análisis de registros, la administración del estado de la IU y la optimización de recursos mediante la reproducción o pausa automática del contenido de video. Compose ofrece varios modificadores para hacer un seguimiento de la visibilidad de los elementos de la IU, como los siguientes:

  • onVisibilityChanged: Este modificador te notifica cuando cambia la visibilidad de un elemento que admite composición. Es ideal para activar una acción o un efecto secundario cada vez que el elemento componible se vuelve visible.
  • onLayoutRectChanged: Este modificador proporciona información sobre los límites de un elemento que admite composición en relación con la raíz, la ventana y la pantalla. Ofrece control de bajo nivel y es la API de base para onVisibilityChanged. El modificador es similar a onGloballyPositioned, pero ofrece un mejor rendimiento y una mayor flexibilidad.

Puedes usar estas APIs con cualquier elemento componible como parte de la cadena de modificadores.

Realiza un seguimiento de los cambios de visibilidad con onVisibilityChanged

Comprender cuándo un elemento es visible o parcialmente visible para un usuario puede ayudarte a realizar un seguimiento de las estadísticas (por ejemplo, el recuento de usuarios), optimizar el rendimiento (recuperar o recuperar previamente datos de la red solo cuando el elemento es visible) o incluso activar eventos (reproducir o pausar videos).

Para recibir una notificación cuando cambie la visibilidad de un elemento, usa el modificador onVisibilityChanged, como se muestra en el siguiente ejemplo:

Text(
    text = "Some text",
    modifier = Modifier
        .onVisibilityChanged { visible ->
            if (visible) {
                // Do something if visible.
            } else {
                // Do something if not visible.
            }
        }
        .padding(vertical = 8.dp)
)

El modificador onVisibilityChanged proporciona un valor booleano que refleja el estado de visibilidad actual del elemento componible. Además, ofrece parámetros como minFractionVisible y minDurationMs, que te brindan un control más detallado sobre cuándo se debe activar la devolución de llamada de visibilidad.

Al igual que con cualquier otro modificador, la secuenciación es importante con el modificador onVisibilityChanged. En el ejemplo anterior, se muestra una función de componibilidad que renderiza texto con padding. Para asegurarte de que el modificador afecte a todo el elemento componible junto con el padding, agrega el modificador onVisibilityChanged antes del modificador padding.

Establece un límite de tiempo en un elemento componible antes de activar la devolución de llamada de visibilidad

En algunas situaciones, es posible que quieras activar una acción solo después de que un elemento haya sido visible para el usuario durante un período determinado. Por ejemplo, puedes reproducir automáticamente un video si el usuario lo vio durante un tiempo.

Para activar una acción después de que un elemento sea visible durante un período definido, usa el parámetro minDurationMs en el modificador onVisibilityChanged. Este parámetro especifica la cantidad mínima de tiempo que un elemento componible debe estar visible de forma continua para que se active la devolución de llamada. Si el elemento que admite composición deja de ser visible antes de que se cumpla la duración, se restablece el temporizador. El valor predeterminado es 0 milisegundos.

En el siguiente fragmento, se cambia el fondo a morado después de que el elemento componible haya sido visible para el usuario durante 3 segundos:

var background by remember { mutableStateOf(PalePink) }
Card(
    modifier = modifier
        // ...
        .onVisibilityChanged(minDurationMs = 3000) {
            if (it) {
                background = MutedPlum
            }
        }
) {

    Box(
        modifier = Modifier
            // ...
            .background(background),
        contentAlignment = Alignment.Center,
    ) {
        // ...
    }
}

Figura 1. El fondo cambia de rosa a ciruela después de que el elemento componible haya estado en pantalla durante 3 segundos de forma continua.

Establece una fracción visible mínima

Establecer una fracción mínima visible para la devolución de llamada de visibilidad del elemento que admite composición es útil cuando se trabaja con contenido desplazable (por ejemplo, LazyColumn) para optimizar la recuperación de datos de los elementos que superan el tamaño de la pantalla.

En esos casos, usa el parámetro minFractionVisible en el modificador onVisibilityChanged para definir la fracción que debe estar en pantalla para que el elemento componible se marque como visible. Admite valores de número de punto flotante que van de 0.0f a 1.0f, y se establece como 1.0f de forma predeterminada. 1.0f significa que el elemento componible debe ser completamente visible en la pantalla o llenar todo el viewport si es más grande que este.

La devolución de llamada recibe true cuando la fracción visible es mayor que minFractionVisible, o cuando el elemento componible es completamente visible o llena el viewport. De lo contrario, recibe false.

LazyColumn(
    modifier = modifier.fillMaxSize()
) {
    item {
        Box(
            modifier = Modifier
                // ...
                // Here `visible` is `true` when more than 20% of the composable is visible.
                .onVisibilityChanged(
                    minFractionVisible = 0.2f,
                ) { visible ->
                    if (visible) {
                        // Call specific logic here.
                        // viewModel.fetchDataFromNetwork()
                    }
                }
                .padding(vertical = 16.dp)
        ) {
            Text(
                text = "Sample Text",
                modifier = Modifier.padding(horizontal = 16.dp)
            )
        }
    }
}

Figura 2: Sin que se establezca minFractionVisible. Figura 3: Con minFractionVisible establecido como 0.2f.

En el ejemplo que se usó antes, se precargan los Androidify Bots de la red antes de que el elemento componible sea completamente visible. En la figura 2, el tercer bot no se carga, ya que el elemento que admite composición no es completamente visible. En la Figura 3, se establece minFractionVisible y el tercer bot se carga antes de que sea completamente visible en la pantalla.

Cómo ocultar un elemento componible y mantener su espacio

Para ocultar un elemento componible sin cambiar el diseño que lo rodea, usa el modificador visible. Cuando pasas false, la función de componibilidad se sigue midiendo, pero no se coloca ni se dibuja. A diferencia de establecer alpha en 0f, visible(false) también quita el elemento del árbol de accesibilidad y, además, inhabilita las interacciones táctiles, a la vez que conserva su espacio de diseño.

En el siguiente ejemplo, se muestra un ícono de marca de verificación que mantiene su espacio mientras está oculto, por lo que el texto que se encuentra junto a él no se mueve:

Row(modifier, verticalAlignment = Alignment.CenterVertically) {
    Icon(
        painter = painterResource(R.drawable.check),
        contentDescription = "Saved",
        modifier = Modifier
            // The icon keeps its space while it's hidden, so the text doesn't move.
            .visible(isSaved)
    )
    Text("Draft", Modifier.padding(start = 8.dp))
}

Usa visible cuando el diseño alrededor de la función de componibilidad no deba moverse a medida que esta aparece y desaparece. Para quitar el elemento componible y su espacio, no lo llames o usa AnimatedVisibility para animar su entrada y salida.