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