Fresco: Transición de elementos compartidos

Creado en 28 mar. 2015  ·  57Comentarios  ·  Fuente: facebook/fresco

La transición de elementos compartidos no parece funcionar.

Probado en un dispositivo Motorola con Android 5.0

Comentario más útil

Aquí está la solución alternativa que utilizo que funciona bien:
https://github.com/bumptech/glide

Todos 57 comentarios

¿Puede darnos más detalles? ¿Qué trataste de hacer exactamente y qué sucedió en su lugar?

En la nueva versión de Android, lollipop, podemos usar un ImageView como una transición de elemento compartido entre actividades. En ese caso, la imagen hace una transición suave de una actividad a la siguiente. Cuando se usa SimpleDraweeView, simplemente desaparece.

El código para probarlo debería ser algo como esto:

tema de la aplicación:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>
    </style>

Activity1 Layout.xml:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/image"
        android:layout_width="@dimen/size_1"
        android:layout_height="@dimen/size_1"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"/>

</RelativeLayout>

Activity2 Layout.xml:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/image"
        android:layout_width="@dimen/size_2"
        android:layout_height="@dimen/size_2"
        android:layout_alignParentRight="true"
        android:layout_alignParentBottom="true"
        android:transitionName="image_transition"/>

</RelativeLayout>

El código para iniciar la segunda actividad:

    Intent intent = new Intent(activity1, Activity2.class);
    ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity1, simpleDraweeView1, "image_transition");
    activity1.startActivity(intent, options.toBundle());

Este código debe hacer una transición entre las actividades donde la imagen se mueve y cambia de tamaño desde la esquina superior izquierda de la actividad 1 a la esquina inferior derecha de la actividad 2. He probado un código similar cargando imágenes de la red y no se muestra la animación.

Creo que esto también está relacionado https://github.com/facebook/fresco/issues/99

Sospecho que esto tiene que ver con adjuntar / separar eventos que la vista obtiene cuando está en transición. Tendremos que investigar eso.

Esto es algo que también puedo confirmar. Las transiciones de elementos compartidos parecen estar rotas en Fresco. Sería genial si pudiéramos arreglar esto, ya que esta es una característica muy importante en el futuro.

También me pasó a mí. Al configurar el atributo xml transtitionName en SimpleDraweeView, el método setImageUri () dejó de funcionar

¿Alguna actualización sobre esto?

Después de que FadeDrawable termine de animar la imagen real, hay un registro:
com.facebook.samples.comparison D / ViewRootImpl ﹕ changeCanvasOpacity: opaque = false

tal vez el changeCanvasOpacity cause que la imagen no se dibuje.

¿Se corrigió el error? También es muy importante para mi proyecto. :)

paquete org.goodev.droidddle.drawee;

import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.view.SimpleDraweeView;

importar android.content.Context;
importar android.graphics.Matrix;
import android.util.AttributeSet;

La clase pública TranslateDraweeView extiende SimpleDraweeView {
public TranslateDraweeView (contexto de contexto) {
super (contexto);
}

public TranslateDraweeView(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public TranslateDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}

public TranslateDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
    super(context, hierarchy);
}

// looks like overwrite this method can fix this issue
// but still don't figure out why
public void animateTransform(Matrix matrix) {
    invalidate();
}

}

@goodev no existe tal método para sobrescribir.

@ shumin0809 solo agrega este método, este es un método público

Veo un comportamiento diferente, pero aún con errores, con SharedElementTransitions. No sé si se trata de un problema similar, relacionado o separado.

_Reproducción _
Configuración bastante estándar para SharedElementTransition:

  • RecyclerView en un fragmento con GridLayoutManager que muestra muchas imágenes como SimpleDraweeViews, estableciendo transitName en ellas dinámicamente en el método de vinculación del marcador de visualización (donde también estoy configurando el uri)
  • OnClick dispara una transición a un fragmento diferente con una sola vista SimpleDrawee y el mismo nombre de transición también se establece dinámicamente

_Esperado _
En cuanto a ImageViews normales (coincidencias de scaleType proporcionadas), animación perfecta de recursos compartidos entre fragmentos

_Observado _
Se produce SharedElementTransition pero hay un parpadeo antes de que aparezca la imagen de destino (parece que la imagen de destino no se ha configurado con suficiente antelación)

_Notas _
Intenté cargar imágenes desde la web y el disco, y la imagen está cargada y en el caché antes de iniciar la transición. El código del fragmento de destino extrae exactamente el mismo uri. Jugué el violín tratando de usar la canalización directamente (y aprendí mucho) pero no pude afectar el resultado.

_Configuración _
Dispositivos: Nexus 5 y Nexus 7 (2013), ambos con Android 5.1.1 (API 22)
Biblioteca y herramientas actualizadas: fresco (0.5.0), Android Studio (1.3 Preview 3 EAP.0), compileSdk (22), herramientas de compilación (22.0.1)

_Realizaciones _
Mientras escribía esta publicación, noté 2 cosas que podrían ser relevantes:

  • Los dos Drawees _son_ tamaños diferentes (esto no es un problema para la transición de ImageViews estándar y no recuerdo nada sobre la búsqueda previa que establezca las dimensiones de destino)
  • De memoria, creo que estoy pasando frescos los fragmentos como Contexto en algún lugar del código, ¿quizás significando que los dos fragmentos tienen cada uno su propio caché?

@jorgemf - ¿Su código publicado no necesita un atributo de nombre de transición coincidente establecido en el diseño de la Actividad 1? https://developer.android.com/training/material/animations.html

_Iniciar una actividad con un elemento compartido _
...
4 - Asigne un nombre común a los elementos compartidos en ambos diseños con el atributo android: transitionName .

Para mi problema, podría ser que necesite posponer la transición. Echaré un vistazo a esto hoy:
http://www.androiddesignpatterns.com/2015/03/activity-postponed-shared-element-transitions-part3b.html

Yo tengo el mismo problema. Utilizo fresco 0.5.3 y SimpleDraweeView no carga la imagen con el atributo " android: transitionName ". ¿Alguien conoce nuestra solución usando Fresco?

@jorgemf Si configura "android-background" en su Activity1 Layout.xml, no funcionará perfectamente, pero funcionará.
Lo configuré en mi prueba: android: background = "@ android: color / transparent "

@LuizGadao Si establece un fondo, pierde todas las ventajas de la biblioteca. Creo que no tiene sentido ya que lo desea para las imágenes descargadas de Internet. No para recursos estáticos como fondo.
Después de probar algunas bibliotecas, picasso me está funcionando bien. Sin problemas en absoluto.

@jorgemf Estoy de acuerdo contigo. Es solo un truco para que funcione.

¿Alguna noticia sobre este?

@LuizGadao, ¿ puede publicar un ejemplo de su XML de solución alternativa?

Gracias por informar de este problema y agradecemos su paciencia. Hemos notificado al equipo central para obtener una actualización sobre este problema. Estamos buscando una respuesta dentro de los próximos 30 días o el problema podría resolverse.

¿Alguna noticia sobre este?

PD:
TranslateDraweeView proporcionado por @goodev no funciona correctamente en algunos dispositivos como XiaoMi2, HuaWei P8. ReenterTransition comienza en la posición incorrecta.

Como dijo boxcounter, Tra slateDraweeView no funciona en HTC One M8, tampoco

Si está utilizando ChangeImageTransform Transition, creo que la transición del elemento compartido falla porque ChangeImageTransform está animando la matriz de ImageView, que creo que no es compatible de forma predeterminada con DraweeView.

El problema que encontré es que el elemento compartido comienza con "fitCenter" mientras que originalmente era "centerCrop".
El proyecto puede reproducir el problema.
https://github.com/JackFan-Z/ActivitySharedElementTransition.git

Aunque agregué una solución
no funciona en mi otro proyecto privado usando fresco.
¿Alguien podría averiguar dónde está el verdadero problema?

Estado de transición de inicio incorrecto
2015-10-01 11 26 34

Antes de la transición
2015-10-01 11 26 50

@ JackFan-Z
Compartir elemento en transición es configurar la vista final a los valores iniciales y animarla a los valores finales.

ImageView normal combinado con ChangeImageTransform capturará los valores inicial y final de la matriz de la imagen y luego animará el cambio de la matriz de la imagen.

Sin embargo, DraweeView anula cierta función relacionada con la matriz de la imagen, por lo que ChangeImageTransform no tendrá ningún efecto en la imagen.

Entonces, lo que terminas es que solo los ChangeBounds surtan efecto.

Actualmente, no encontré forma de manipular la matriz de imagen de DraweeView. Incluso el setActualImageMatrix se ha marcado como obsoleto. Supongamos que no está obsoleto y funciona exactamente como el valor predeterminado setImageMatrix del ImageView predeterminado. Aun así, no es muy fácil animar el cambio debido al hecho de que no tiene ninguna forma de cambiar la matriz después de haber configurado DraweeViewHierarchy . Por lo tanto, debe crear un nuevo DraweeViewHierarchy en cada llamada de onAnimationUpdate .

No sé por qué DraweeView se implementa de esta manera. Y creo que la posible solución actual es recuperar el mapa de bits subyacente y crear otro ImageView para hacer la transición ChangeImageTransform .

@soapsign
Gracias por tu comentario.

En realidad, en mi proyecto privado, intenté crear un ImageView ficticio que toma el mismo mapa de bits que el elemento compartido. El problema sigue existiendo.
No estoy seguro de si el problema al que me enfrento está relacionado con el fresco o no.
Pero es seguro que puedo reproducir el mismo problema fácilmente con SimpleDraweeView.

ChangeImageTransform usa las dimensiones intrínsecas para determinar la matriz de transformación. Nuestra implementación de DraweeView usa un DraweeHierarchy que tiene dimensiones intrínsecas igual a -1 para width y height . Esto se debe a que Drawee ya aplica el escalado de tipo de escala correcto y, por lo tanto, no hay necesidad de una vista para hacerlo. Además, ImageView solo puede aplicar un tipo de escala, mientras que la jerarquía dibujable puede usar tipos de escala separados para cada rama de imagen (marcador de posición, imagen de falla, imagen real, etc.). Devolver las dimensiones intrínsecas reales a la vista solo aumenta el riesgo de tener errores de tamaño.
Si desea que la transición funcione, debe usar ChangeBounds .

¿Qué tal si agregamos una nueva opción como " fresco: ImageMatrixSrc = actual "?

@boxcounter Por el momento pensamos que lo que tenemos ahora está bien. Pero puede crear una solicitud de extracción para su propuesta :)

@massimocarli ChangeBounds funciona bien solo cuando la imagen compartida tiene el mismo tamaño en ambas actividades / vistas. Pero cuando se debe cambiar el tamaño de la imagen durante la transición, se recorta y se ve mal.
¿Qué te propones hacer de esa manera? ChangeImageTransform resuelve esto, pero no funciona en DraweeView.

Aquí igual...

@massimocarli ChangeBounds no es lo suficientemente bueno.

Esto es lo que estoy tratando de lograr (esto es usando ImageView): https://gfycat.com/HideousEarlyAndalusianhorse

Así es como se ve usando SimpleDraweeView: https://gfycat.com/PracticalCorruptGrouper
Observe la forma en que la imagen original cambia de tamaño incorrectamente detrás de la imagen animada.

Así es como se ve solo con ChangeBounds como transición: https://gfycat.com/SorrowfulExemplaryAntlion

Hola amigos, tengo el mismo problema. ChangeBounds no funciona correctamente. Si hay una solución alternativa o una solución, infórmenos. La transición de elementos compartidos es una de las mejores cosas que introdujo el diseño de materiales y fresco es una de las mejores bibliotecas que he usado hasta ahora. Permita que los desarrolladores utilicen ambos sin problemas.

¿Alguien ha podido encontrar una solución alternativa ya que Fresco no solucionará esto?

Aquí está la solución alternativa que utilizo que funciona bien:
https://github.com/bumptech/glide

Hola todos,

El método ChangeBounds en sí no es suficiente y me sorprende la respuesta de Facebook de que el estado actual de las transiciones de elementos compartidos está bien.

Finalmente encontré una solución lo suficientemente simple que parece funcionar para mí en un proyecto de muestra.
Dado que la transición ChangeBounds no actualiza el diseño en sí a través de onMeasure () sino a través de onSizeChanged (), que actualmente no está anulado por ninguna vista de librado, la escala del dibujable nunca se actualiza durante la transición.

Aquí está nuestro CustomDraweeView que actualiza el TopLevelDrawable durante la transición:

public class CustomDraweeView extends SimpleDraweeView {

    public CustomDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
        super(context, hierarchy);
    }

    public CustomDraweeView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    <strong i="10">@Override</strong>
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Drawable drawable = getTopLevelDrawable();
        if (drawable != null) {
            drawable.setBounds(0, 0, w, h);
        }
    }
}

Aquí está el xml del conjunto de transición que necesitará inflar:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:duration="<strong i="14">@android</strong>:integer/config_mediumAnimTime"
    android:transitionOrdering="together"
    tools:targetApi="LOLLIPOP" >
    <changeBounds
        android:interpolator="<strong i="15">@android</strong>:interpolator/accelerate_decelerate"/>
    <changeTransform
        android:interpolator="<strong i="16">@android</strong>:interpolator/accelerate_decelerate"/>
</transitionSet>

El único inconveniente que tengo con este método es cuando el tipo de escala de los elementos de diseño no coincide entre los fragmentos o las actividades, lo que debe evitar de todos modos si desea utilizar transiciones de elementos compartidos.

@massimocarli @tyronen
¿Alguien en Facebook puede proporcionar una idea de por qué DraweeView no anula actualmente este método y de los posibles problemas que podrían surgir con esta modificación? Si no se encuentra ninguno, me complacerá crear una solicitud de extracción para eso.

¡Hola a todos! En la nueva versión 0.10 de Fresco con transformación ScaleType personalizada entre diferentes ScaleTypes es trivial. Aquí está mi implementación
https://gist.github.com/burzumrus/a589aa7e36ca003ddaf2334218c50ad0

El uso es simple

TransitionSet transitionSet = new TransitionSet();
transitionSet.addTransition(new ChangeBounds());
transitionSet.addTransition(new DraweeTransform(ScalingUtils.ScaleType.CENTER_CROP, ScalingUtils.ScaleType.FIT_CENTER));
getWindow().setSharedElementEnterTransition(transitionSet);

@burzumrus ¡ eso es increíble! Gracias por implementarlo. Eso es exactamente lo que tenía en mente con InterpolatingScaleType . Considere hacer una solicitud de extracción para Fresco si aún no lo ha hecho.

@plamenko Estoy usando fresco 0.12 y

getWindow().setSharedElementEnterTransition(DraweeTransition.createTransitionSet(
                    ScalingUtils.ScaleType.CENTER_CROP, ScalingUtils.ScaleType.CENTER_CROP));
getWindow().setSharedElementEnterTransition(DraweeTransition.createTransitionSet(
                    ScalingUtils.ScaleType.CENTER_CROP, ScalingUtils.ScaleType.CENTER_CROP));

La animación funciona perfectamente. Pero al volver a la primera actividad, la imagen desaparece.

¿Alguien probó estos con animaciones de fragmento a fragmento? Porque no parece funcionar en la v0.12.
Editar : ¿es posible que RecyclerView cause problemas?
Edición 2 : Parece que el problema es que ChangeBounds sí solo usa las coordenadas X e Y _window_ si el reparenting se establece en true. Establecerlo a través de ChangeBounds setReparenting(true) está obsoleto y se recomienda ChangeTransform su lugar. Entonces, para RecyclerView , también se requiere transitionSet.addTransition(new ChangeTransform()); . (La animación que regresa parece mala aún, pero al menos la animación que ingresa está bien ( excepto que el tipo de escala no tiene ningún efecto al cambiar startValues.view a endValues.view en createAnimator(...) resuelve esto) con esta.)

@Gericop y @ ladia12 0.12 funcionan bien en mi proyecto en animaciones de fragmento a fragmento.
Lo uso también en RecyclerView.
El caso es que solo puede usar la transacción de fragmento 'reemplazar'. No puede usar la transacción 'agregar'.
Si puede ayudarlo, aquí hay un ejemplo (sin fresco) de transición de fragmento a fragmento que me ayudó a comenzar con algo que funcionó (puede descargar el código del proyecto en github)
http://www.androidauthority.com/using-shared-element-transitions-activities-fragments-631996/

@sperochon Yo uso replace y está en un RecyclerView pero no funciona (y honestamente, es sorprendente que funcione para ti, ¿tal vez usas una versión diferente de RecyclerView? Yo uso v24.1.1). Tuve que hacer algunos cambios para que las animaciones funcionaran:

  • agregó ChangeTransform al conjunto de transición a través de transitionSet.addTransition(new ChangeTransform());

    • esto se debe al hecho de que ChangeBounds informa la posición incorrecta de la vista de inicio en un RecyclerView (siempre devuelve las coordenadas X, Y del primer elemento)

  • en createAnimator(...) reemplace if (mFromScale == mToScale) con if(mFromScale == mToScale && startBounds.equals(endBounds))

    • la transformación no sucederá de lo contrario si los dos librados comparten el mismo tipo de escala, aunque sus tamaños no sean los mismos

  • en createAnimator(...) reemplace final GenericDraweeView draweeView = (GenericDraweeView) startValues.view; con final GenericDraweeView draweeView = (GenericDraweeView) endValues.view; (tenga en cuenta el startValues -> endValues cambio)

    • use el librado final en lugar del inicial

  • en AnimatorUpdateListener después de la llamada scaleType.setValue(fraction) , inserte las siguientes líneas:
Drawable drawable = draweeView.getTopLevelDrawable();

if (drawable != null) {
    drawable.setBounds(0, 0, draweeView.getWidth(), draweeView.getHeight());
}

Esta última pieza de código se basa en la solución de @Aohayou (porque no pude hacer funcionar CustomDraweeView ).
Probado esto en Android 5.0.2 con soporte lib versión v24.1.1.

TENGA EN CUENTA que esta solución no funcionará si anima entre imágenes con los mismos tamaños.

@Gericop Aquí hay una demostración que funciona bien. Lo acabo de enviar a github. Intenté limpiar el código al máximo. Tenga cuidado: utilicé solo 1 imagen en mi vista de reciclador porque el nombre de transición tiene que ser diferente en cada elemento de la vista de reciclador para que Fresco funcione. Entonces, para simplificar, usé solo 1 imagen con 1 nombre de transición.
https://github.com/sperochon/DemoFrescoFragment2Fragment

¡Espero que esto ayude!

@sperochon Pruébelo con varias imágenes.
Por cierto, probé tu demo con una fuente sin modificar. Este es el resultado:

device-2016-08-14-220810_1

Esto está completamente mal. La vista final comienza desde una posición diferente y el tipo de escala no tiene ningún efecto. No sé cómo se puede decir que "funciona bien" porque claramente no es así.

@Gericop Acabo de actualizar el código. Olvidé especificar un diseño diferente para el fragmento final. Por favor, inténtalo de nuevo.

@sperochon En el emulador API 23, funciona bien. En mi dispositivo (API 21) no es así. También lo probé en un emulador API 21, tampoco funciona allí.
Entonces, el punto es: la implementación actual no funciona en API 21 (no la probé en API 22), pero funciona en API 23.

Editar : su demostración solo prueba las transiciones ChangeBounds y ChangeTransform predeterminadas, no la implementación DraweeTransition proporcionada por Facebook.

Desafortunadamente, tienes razón ... Lo he probado en mis dispositivos:
Android 5.0 + Fresco v0.11 / v0.12 -> KO
Android 6.0 + Fresco v0.11 / v0.12 -> OK
No me di cuenta antes ...

@Gericop @sperochon He escrito una publicación de blog en medio sobre esto. Por favor, vea si ayuda.

@ ladia12 Esa publicación no tiene nada que ver con el problema que estaba (estábamos) enfrentando ... La entrada de tu blog trata sobre la transición de _inter- Actividad _, mientras que mi problema está relacionado con el _inter- Fragmento _. Además, el error real está en cómo API 21 maneja las transiciones ChangeBounds y / o ChangeTransform donde Facebook suministró DraweeTransition tampoco ayuda. Mi solución, por otro lado, supera esto, si las imágenes de origen y destino tienen diferentes dimensiones (ancho y / o alto).

Sólo por información:
Android 5.0 + Fresco v0.11 / v0.12 / 0.13 -> KO
Android> = 5.1 + Fresco v0.11 / 0.12 / 0.13 -> OK

@ ladia12 ¿Cómo

@dbrant Tengo el mismo problema, ¿ha encontrado alguna forma de resolverlo?

Ver # 1446

@ ladia12 ¿Cómo

@ ladia12 ¿Cómo

Terminé usando Picasso para la transición de elementos compartidos. No fue arreglado
en Fresco. Entonces, Picasso es liviano y no hay ningún problema para usarlo.
junto con Fresco.

El miércoles 19 de junio de 2019 a las 5:11 p. M. Bembem1011 [email protected] escribió:

@ ladia12 https://github.com/ladia12 ¿Cómo resolvió el problema de
¿Desaparece la imagen original al volver a la primera actividad? Mi
La imagen original está en el visor de RecyclerView.

-
Recibes esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/facebook/fresco/issues/22?email_source=notifications&email_token=AAXQ5WYUP5KBJYNBOZX7CCDP3ILM5A5CNFSM4A6ZMH32YY3PNVWWK3TUL52HS4DFVREXP63JSMVBW5 ,
o silenciar el hilo
https://github.com/notifications/unsubscribe-auth/AAXQ5W5EXO5SV4R2PXVTG7LP3ILM5ANCNFSM4A6ZMH3Q
.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

zewenwang picture zewenwang  ·  4Comentarios

eldk picture eldk  ·  3Comentarios

sungerk picture sungerk  ·  3Comentarios

ykostova picture ykostova  ·  3Comentarios

stevenmtang picture stevenmtang  ·  3Comentarios