Generalidades

Crea una lista circular en Jetpack Compose | Autor Francesc Vilarino Guell | Septiembre 2021

Pluma Francis Villarino

Recientemente encontré una pregunta en StackOverflow sobre cómo implementar una lista circular en Jetpack Compose. Se trata básicamente de una lista en la que los elementos se mueven horizontalmente de acuerdo con su posición vertical como si siguieran una ruta circular. El siguiente gif ayudará a explicar esto:

En este artículo, aprenderemos cómo crear esta lista.

El primer paso para crear este bucler list está creando un Composable, solo dibujará una lista regular de elementos, una vez que lo tengamos, podremos comenzar a ajustar gradualmente el Composable para que podamos lograr los resultados que queremos.

Al crear componibles personalizados, una herramienta poderosa es Layout Composable, equivalente a personalizado ViewGroup En el sistema de vistas.Utilizar uno Layout Tengamos un control total sobre la ubicación de los elementos en Composable, y esto es lo que estamos a punto de comenzar.

Empecemos por crear un Composable simple que presente a sus hijos verticalmente, básicamente estamos creando un Column Como nuestro punto de partida. El código para lograr esto es el siguiente:

Vamos a ver:

  1. -Creamos nuestra lista circular y definimos 4 parámetros, el número de elementos visibles a renderizar (es decir, cuántos elementos son visibles en nuestro contenedor a la vez), uno Modifier Para que el cliente pueda personalizar las propiedades de nuestro Composable, un fraction Esto mostrará qué tan redondo es nuestro camino (y 1f Significa un bucle perfecto) y, finalmente, una lambda de contenido combinable.
  2. Primero, realizamos algunas comprobaciones de cordura para verificar los parámetros de entrada y descartamos cuando estos parámetros no son válidos.
  3. A continuación usamos Layout Se puede combinar para colocar elementos, a través de Modifier Y el contenido lambda que recibimos como parámetro.esta Layout Se puede combinar, también necesita uno. MeasurePolicy lambda decir Layout Cómo medir y localizar a su hijo.
  4. En nuestra lambda primero, calculamos qué tan alto debe estar cada elemento en función de las restricciones pasadas y la cantidad de elementos visibles a la vez.
  5. A continuación creamos un Constraints Objetos con ancho y alto fijos, son el ancho de nuestro Composable y el alto del artículo que acabamos de calcular.
  6. Una vez que tengamos estos Constraints Los usamos para medir a los niños; esto devolverá una lista Placeables, lo arreglaremos más tarde.
  7. Ahora que tenemos todas las piezas que necesitamos, es hora de diseñar estos elementos llamando layout.
  8. Primero, calculamos el desplazamiento vertical del elemento porque queremos que el primer elemento esté centrado en el contenedor cuando el elemento se muestra por primera vez. Para esto, el desplazamiento debe ser la altura del contenedor menos la altura del niño, y luego dividido por 2.
  9. Ahora iteramos nuestro Placeables para colocarlos.
  10. Desplazamiento vertical de cada uno Placeable Es el desplazamiento calculado en el paso 8, más el número de elementos anteriores, multiplicado por la altura del elemento.
  11. Una vez que tengamos el offset vertical, podemos posicionar los elementos, ahora solo necesitamos colocarlos en 0 en el eje horizontal, lo arreglaremos más adelante.

Esto nos proporciona un diseño muy básico, mostrando nuestro contenido verticalmente, con el primer elemento centrado. La primera solución no se ha optimizado, aunque puede que solo haya unos pocos elementos visibles en la pantalla, pero los colocaremos todos, en el caso de que se caigan de la pantalla. Resolveremos este problema en un paso posterior.

Con esto, obtuvimos este resultado:

Los resultados hasta ahora son aburridos, continuemos.

Se creó una lista estática en el paso anterior, y podemos ver que hay más elementos en la lista, pero actualmente no podemos desplazarlos. Resolvamos este problema como el siguiente paso de nuestro viaje.

Primero crearemos un State Para nuestro Composable, porque esto facilitará el manejo de su lógica.Como describí en un artículo anterior, proporcione una State La interfaz y la implementación que se utilizará por defecto, para que el cliente pueda personalizar y componer cuando lo desee; de ​​lo contrario, se utilizará por defecto la implementación proporcionada.

Definamos nuestro estado y la implementación predeterminada:

1. Configuración de estado

Nuestro estado necesita algunos parámetros para el cálculo; en lugar de pasarlos individualmente, creamos un data class Podemos usarlo para empacarlos.

2. Interfaz de estado

A continuación, definimos nuestra interfaz. Exposición de la interfaz:

  • El desplazamiento vertical actual del elemento que se mostrará. Transferimos la responsabilidad de este cálculo de Composable a State, de modo que Composable solo se encarga de renderizar el proyecto, y State hará todos los cálculos.
  • El primer elemento visible en nuestro diseño.
  • El último elemento visible en nuestro diseño. Usaremos este atributo y el anterior para saber qué elementos colocar y cuáles ignorar.
  • Una especie de suspend La función alinea la lista en una posición determinada y proporciona un desplazamiento vertical en píxeles.
  • Una especie de decayTo Usaremos este método para animar la lista más tarde cuando el usuario arrastre el elemento.
  • Una especie de stop Detenga cualquier método de animación saliente; cuando el usuario haga clic en la lista, activaremos este método.
  • Un método para devolver el desplazamiento (xey) de un elemento dado en una lista, identificado por su índice en la lista.
  • El último método es proporcionarnos el estado de la configuración que acabamos de definir.

3. Ejecución nacional

A continuación, tenemos la implementación de nuestro estado, si el usuario de la lista circular no proporciona una implementación personalizada, el comportamiento predeterminado. Algunas cosas que vale la pena señalar en esta implementación son:

  • Usamos uno Animatable Realice un seguimiento del desplazamiento actual en la lista.
  • esta snapTo Delegado de método a Animatablede snapTo, Pero forzamos estos elementos para no permitir que los usuarios se desplacen por encima o por debajo del primer y último elemento.
  • esta offsetFor El método es el mismo que nuestro cálculo anterior en Composable, ahora solo proporciona un desplazamiento vertical.
  • Proporcionamos un Saver Para nuestro estado, si la aplicación se restaura después de haber sido eliminada, se puede conservar y restaurar.

4.- Fábrica de propiedad estatal

Finalmente, tenemos una función para recordar nuestro estado y devolver la instancia.

Ahora estamos listos para agregar la función de arrastre a la lista circular.Para habilitar el arrastre, crearemos Modifier La extensión a la que llamaremos drag. Vamos a revisar Modifier Primero, luego veremos su efecto real:

  1. Creamos una extensión Modifier Llama drag Llamamos pointerInput De esta manera podemos manejar eventos táctiles en Composable.
  2. Hacemos un bucle para que una vez que se complete el evento de arrastre, esperemos al siguiente.
  3. Esperamos a que se active un evento de puntero.Esto es un suspend Una vez que el usuario interactúa con Composable, la función se reanudará.
  4. Primero, detenemos cualquier animación saliente en Composable.
  5. A continuación, comenzamos a usar verticalDrag Método, otro suspend Llame a nuestra función lambda siempre que el usuario arrastre verticalmente.
  6. Siempre que se llama a lambda, actualizamos el desplazamiento vertical.
  7. Luego alineamos la lista con el nuevo desplazamiento.
  8. Finalmente consumimos este evento.

Ahora solo necesitamos actualizar nuestra lista circular para usar drag Modifier Y usa nuestra clase estatal:

Los cambios son bastante pequeños:

  • Actualizamos nuestra firma para obtener un estado y, por defecto, usamos nuestra implementación.
  • Brindamos al país la información requerida.
  • Limitamos Placeables Colocamos los que son visibles.
  • Usamos país offsetFor Para localizar al niño.

Este es el resultado:

Básicamente, copiamos el contenido desplazable. Column Siempre, pero nada más. Aunque el contenido se desplace, mientras levantemos el dedo, se detendrá. Agreguemos una animación de decaimiento para que la lista se detenga de una manera más orgánica.

Para agregar la animación de decaimiento a nuestra lista, necesitamos calcular la velocidad a la que el usuario arrastra la lista y luego calcular la posición final donde necesitamos continuar la animación mientras reducimos la velocidad. La mayoría de ellos son manejados por la API de animación de Jetpack Compose. Nuestra responsabilidad es calcular la velocidad inicial, el desplazamiento final y luego activar la animación de atenuación.

Actualicemos nuestro drag Modifier Calcule la velocidad y proporciónela a la expansión de nuestro estado:

Para agregar atenuación, debemos realizar los siguientes cambios:

  • Instanciamos un splineBasedDecay Usaremos para calcular el desplazamiento final del objeto que necesitamos animar.
  • Instanciamos un VelocityTracker Cuando se detecta un gesto de puntero, lo usaremos para rastrear la velocidad de arrastre.
  • Siempre que obtenemos una actualización de arrastre, pasamos la información de arrastre a VelocityTracker.
  • Cuando se completa el gesto de arrastre, calculamos la velocidad vertical del arrastre del usuario.
  • A esta velocidad, calculamos qué tan lejos debemos desplazarnos en función de la posición de desplazamiento actual.
  • Finalmente, proporcionamos la velocidad y el desplazamiento para desplazarnos a nuestro estado.

Ahora veamos cómo el estado maneja estos parámetros para atenuar la animación de arrastre:

Agregamos lo siguiente al estado:

  1. Instanciamos un decayAnimationSpec Lo usaremos para animar la lista para que se detenga después de que el usuario levante el dedo.Puedes especificar aquí dampingRatio (Cuánto rebotar cuando se detiene), y stiffness, La dificultad de arrastrar la lista. La lista con alta rigidez se detendrá más rápido, mientras que la lista con baja rigidez se desplazará más lejos.
  2. Implementamos decayTo método. Aquí, nos aseguramos de que el valor objetivo final esté dentro del rango válido, y luego nos aseguramos de terminar con el elemento centrado en el medio de la lista. Básicamente lo que hacemos es calcular el índice del elemento en un pergamino dado, y luego si el elemento es menos de la mitad visible, nos desplazaremos al siguiente (porque será más de la mitad visible y por lo tanto más cerca del centro) .

Ahora que tenemos una lista que se puede arrastrar, se detendrá cuando sueltemos el dedo:

A continuación, agregaremos una ruta circular al proyecto. Para calcular dónde colocar el artículo en el eje horizontal, calcularemos el radio del círculo imaginario incrustado en nuestro contenedor (la misma altura que nuestro contenedor), y luego usaremos la conocida fórmula de Pitagoras para determinar el desplazamiento horizontal. .Es más fácil mostrar que explicar, así que veamos cómo podemos modificar nuestro offsetFor Cómo calcular la compensación correcta:

  1. Primero calculamos cuánto se puede desplazar verticalmente un elemento, lo que determinará cuándo el elemento está en la coordenada horizontal 0.
  2. A continuación, calculamos la distancia vertical del elemento actual desde el centro de la pantalla.
  3. A continuación, definimos el radio del círculo que imaginamos, el círculo es tan alto como nuestro contenedor, por lo que el radio es la mitad.
  4. Los incrementos verticales que calculamos anteriormente deben ajustarse, y los incrementos están limitados a la mitad de la altura del contenedor, pero cuando los elementos se desplazan fuera de la pantalla, pueden desplazarse más lejos, por lo que ajustamos los incrementos en consecuencia aquí.
  5. Finalmente, calculamos el desplazamiento en el eje horizontal en función del radio y el desplazamiento vertical.
  6. Aplicamos la fracción del círculo a la coordenada x y la devolvemos.

Podemos agregar algunos otros ajustes a nuestro Composable. También podemos agregar un rebasamiento para que los usuarios puedan arrastrar sobre el primer o el último elemento, y cuando suelten el dedo, se animará de nuevo al primer o último elemento.

Podemos proporcionar esta información a nuestro estado (cuánto se excede, el número de artículos) y luego ajustar nuestro snapToPermita tantos métodos de sobreimpulso:

  1. Actualizamos nuestro estado para tomar overshoot Parámetros, expresados ​​en términos de número de elementos.
  2. Calculamos el desplazamiento mínimo sobre el primer elemento en función del número de elementos que se pueden superar.
  3. Nuevamente calculamos el desplazamiento máximo debajo del último elemento en función del número de elementos de sobreimpulso.

Entonces nuestra lista está completa, el código completo es el siguiente:

Aquí se muestra un ejemplo de uso:

También podemos hacer algunos ajustes, por ejemplo, podemos cambiar el tamaño de los elementos para hacerlos más grandes a medida que se acercan al centro del contenedor, o disminuir su alfa a medida que se alejan del centro. Estos ajustes adicionales se dejan como ejercicio para el lector.

Espero que le resulte útil, nos vemos en el próximo artículo.

LEER  Cree un ilder MaterialAlertDialogBu ​​personalizado en ANDROID KOTLIN | Autor: Bhavya Varmora | Junio ​​de 2021

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba