De Dribbble a Android Motion



En Internet, hay muchas plantillas animadas interesantes con hermosas interfaces de usuario de aplicaciones móviles, pero no hay muchos ejemplos con la implementación de estas interfaces. A pesar de la abundancia de varios marcos y herramientas incorporados en el SDK de Android, a menudo no es fácil para un desarrollador novato implementar una hermosa interfaz de usuario, incluso con una plantilla preparada.

En este artículo, intentaremos implementar la interfaz de usuario desarrollada por el diseñador Ivan Parfyonov para el estudio PLATES.


Primero, cree dos fragmentos: RecyclerFragment y DetailsFragment .


Marco de transición de Android?


El marco de transición de Android funciona bien, pero hay algunos matices. En primer lugar, queremos que todo funcione para nosotros, al menos en API 19, y en segundo lugar, necesitamos animar varios elementos de usuario al mismo tiempo y algunos de ellos están presentes en un solo fragmento. Por lo tanto, implementamos la animación del elemento de transición (transición de elemento compartido) manualmente usando ViewPropertyAnimator .

Todo en orden


  1. Calculamos las coordenadas finales del elemento seleccionado de la lista (sus coordenadas en DerailsFragment ), la lista es un RecyclerView ;
  2. Guardamos las coordenadas actuales (coordenadas en RecyclerFragment ) y las pasamos a DetailsFragment (esto es necesario para la animación inversa con API <21);
  3. Crear una copia del elemento seleccionado de la lista;
  4. Hacemos que el elemento seleccionado sea invisible (no una copia, sino el elemento en sí);
  5. Agregue la copia creada en el paso 3 al diseño raíz del fragmento principal, en nuestro caso, este es RecyclerFragment ;
  6. Comenzamos la animación de los elementos restantes de la interfaz y movemos la copia creada a las coordenadas finales del paso 1;
  7. Cuando termine la animación, cree una transacción y muestre DetailsFragment ;
  8. Comenzamos la animación de los elementos de la interfaz en DetailsFragment .

Animación de elementos de la IU


Para animar la Toolbar crearemos una View adicional en el RecyclerFragment y la RecyclerFragment detrás de la pantalla en la parte superior. Esta View se ViewPropertyAnimator en el contenedor de la Toolbar en el DetailsFragment (color azul en gif) usando ViewPropertyAnimator .

 <View android:id="@+id/details_toolbar_helper" android:layout_width="wrap_content" android:layout_height="@dimen/details_toolbar_container_height" android:background="@color/colorPrimary" app:layout_constraintTop_toTopOf="parent"/> // In RecyclerFragment details_toolbar_helper.translationY = -details_toolbar_helper.height 

imagen

BottomNavigationView animaciones BottomNavigationView y RecyclerView también se implementan usando ViewPropertyAnimator , nada complicado (cambio de transparencia y movimiento).

Un poco del marco de transición


En palabras simples, el marco de transición de Android, cuando comienza a animar el elemento de transición, crea una copia del contenido de este elemento de transición (algo así como la pantalla de impresión), crea un ImageView a partir de esta copia, luego agrega esta imagen a la capa de superposición adicional en la capa de superposición el fragmento llamado y comienza la animación.

El marco de transición de Android no es muy adecuado para nosotros, porque cuando comienza la animación del elemento de transición, todos los demás elementos de la interfaz de usuario en el fragmento se destruyen y no podemos animarlos. Es decir cuando hacemos clic en un elemento de la lista en RecyclerFragment para abrir DetailsFragment e iniciar la animación de transición, todos los demás elementos de la interfaz en RecyclerFragment destruyen sin animación.

Para obtener el resultado deseado, crearemos manualmente una copia del elemento seleccionado de la lista, lo agregaremos a la capa superpuesta y luego lo animaremos. Pero aquí aparece un pequeño problema, la documentación para el ViewGroupOverlay add(view: View) dice:
Si la vista tiene un elemento primario, la vista se eliminará de ese elemento primario antes de agregarse a la superposición.

Pero para RecyclerView esto no funciona, el elemento seleccionado no se elimina de RecyclerView después de agregarlo a la capa de superposición.

Esto es lo que sucede cuando agregamos el elemento seleccionado a la capa de superposición:



Y necesitamos esto:



Por lo tanto, no utilizaremos la capa de superposición, y agregaremos la copia inmediatamente al diseño raíz. Cree una copia del contenido del elemento seleccionado, agréguelo a ImageView y configure las coordenadas:

 fun View.copyViewImage(): View { val copy = ImageView(context) val bitmap = drawToBitmap() copy.setImageBitmap(bitmap) //  pre-Lollipop   ,   card view  ,      card view return (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CardView(context).apply { cardElevation = resources.getDimension(R.dimen.card_elevation) radius = resources.getDimension(R.dimen.card_corner_radius) addView(copy) } } else { copy }).apply { layoutParams = this@copyViewImage.layoutParams layoutParams.height = this@copyViewImage.height layoutParams.width = this@copyViewImage.width x = this@copyViewImage.x y = this@copyViewImage.y } } 


¿Por qué crear una copia si solo puede animar el elemento directamente seleccionado de la lista?

Porque RecyclerView también estará animado y, en consecuencia, todos sus elementos, incluido el seleccionado, que queremos animar por separado.

Después de eso, agregue una copia al marcado raíz e inicie la animación.

 override fun onClick(view: View) { val fragmentTransaction = initFragmentTransaction(view) val copy = view.createCopyView() root.addView(copy) view.visibility = View.INVISIBLE startAnimation(copy, fragmentTransaction) } 


Y aquí está lo que tenemos:



Línea de meta


La animación GIF anterior tiene lugar en un RecyclerFragment , y después de su finalización debemos mostrar DetailsFragment .

 .withEndAction { fragmentTransaction?.commitAllowingStateLoss() } 

¿Por qué estamos usando commitAllowingStateLoss ?

Si no lo usa y, en el momento de la animación, habrá, por ejemplo, un cambio en la orientación de la pantalla, obtendremos IllegalStateExeption . Aquí está bien escrito al respecto.

A continuación, comenzamos la animación de los elementos necesarios de la interfaz de usuario en DetailsFragment .

Ejecútalo todo junto




No es exactamente lo mismo que el original, pero se ve similar.

Ejemplos


El código fuente está disponible en GitHub , y el artículo también está disponible en inglés .

Gracias por su atencion!

Source: https://habr.com/ru/post/es423235/


All Articles