Fresco: Transição de elemento compartilhado

Criado em 28 mar. 2015  ·  57Comentários  ·  Fonte: facebook/fresco

A transição de elementos compartilhados não parece funcionar.

Testado em um dispositivo motorola com Android 5.0

Comentários muito úteis

Aqui está a solução alternativa que utilizo que funciona bem:
https://github.com/bumptech/glide

Todos 57 comentários

Você pode nos dar mais detalhes? O que exatamente você tentou fazer e o que aconteceu em vez disso?

Na nova versão do Android, lollipop, podemos usar um ImageView como uma transição de elemento compartilhado entre as atividades. Nesse caso, a imagem faz uma transição suave de uma atividade para a próxima. Ao usar o SimpleDraweeView, ele simplesmente desaparece.

O código para testá-lo deve ser algo assim:

tema do aplicativo:

    <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>

O código para iniciar a segunda atividade:

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

Este código deve fazer uma transição entre as atividades onde a imagem se move e redimensiona do canto superior esquerdo da atividade 1 para o canto inferior direito da atividade 2. Eu testei um código semelhante carregando imagens da rede e ele não exibe a animação.

Acho que isso também está relacionado https://github.com/facebook/fresco/issues/99

Suspeito que isso tenha a ver com eventos de anexação / desconexão que o modo de exibição obtém durante a transição. Teremos que investigar isso.

Isso também posso confirmar. As transições de elementos compartilhados parecem estar interrompidas no Fresco. Seria ótimo se pudéssemos consertar isso, pois esse é um recurso muito importante no futuro.

Aconteceu comigo também. Ao definir transtitionName xml attr para SimpleDraweeView, o método setImageUri () parou de funcionar

Alguma atualização sobre isso?

Após o FadeDrawable terminar de animar a imagem real, há um registro:
com.facebook.samples.comparison D / ViewRootImpl ﹕ changeCanvasOpacity: opaque = false

talvez o changeCanvasOpacity faça com que a imagem não seja desenhada.

O bug foi corrigido? É muito significativo para o meu projeto também. :)

package org.goodev.droidddle.drawee;

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

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

public class TranslateDraweeView extends 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 não existe tal método para sobrescrever.

@ shumin0809 basta adicionar este método, é um método público de ocultação para a transição.

Estou vendo um comportamento diferente, mas ainda problemático, com SharedElementTransitions. Não sei se este é o mesmo problema, relacionado ou separado.

_Reprodução _
Configuração bastante padrão para uma SharedElementTransition:

  • RecyclerView em um fragmento com GridLayoutManager exibindo muitas imagens como SimpleDraweeViews, definindo transactionName nelas dinamicamente no método de vinculação do viewholder (onde também estou definindo o uri)
  • OnClick dispara uma transição para um fragmento diferente com uma única visualização SimpleDrawee e o mesmo nome da transição também definido dinamicamente

_Esperado _
Quanto a ImageViews normais (correspondências de scaleType fornecidas), animação contínua de recurso compartilhado entre fragmentos

_Observado _
SharedElementTransition ocorre, mas há uma oscilação antes que a imagem de destino apareça (parece que a imagem de destino não foi definida com antecedência suficiente)

_Notas _
Tentei carregar imagens da web e do disco, e a imagem é carregada e está no cache antes de iniciar a transição. O código do fragmento de destino está puxando exatamente o mesmo uri. Eu tentei usar o pipeline diretamente (e aprendi muito), mas não consegui afetar o resultado.

_Setup _
Dispositivos: Nexus 5 e Nexus 7 (2013), ambos executando Android 5.1.1 (API 22)
Biblioteca e ferramentas atualizadas: fresco (0.5.0), Android Studio (1.3 Preview 3 EAP.0), compileSdk (22), ferramentas de compilação (22.0.1)

_Realizações _
Enquanto escrevo esta postagem, percebi 2 coisas que podem ser relevantes:

  • Os dois Drawees _são_ tamanhos diferentes (isso não é um problema para a transição de ImageViews padrão e não me lembro de nada sobre a pré-busca que define as dimensões de destino)
  • De memória, acho que estou passando os fragmentos do afresco como Contexto em algum lugar do código, talvez significando que cada um dos dois fragmentos tem seu próprio cache ??

@jorgemf - seu código postado não precisa de um atributo de transição https://developer.android.com/training/material/animations.html

_Iniciar uma atividade com um elemento compartilhado _
...
4 - Atribua um nome comum aos elementos compartilhados em ambos os layouts com o atributo android: transactionName .

Para o meu problema, pode ser que eu precise adiar a transição. Vou dar uma olhada nisso hoje:
http://www.androiddesignpatterns.com/2015/03/activity-postponed-shared-element-transitions-part3b.html

Estou com o mesmo problema. Estou usando o fresco 0.5.3 e SimpleDraweeView e não carrego a imagem com attr " android: silenceName". Alguém conhece outra solução usando Fresco?

@jorgemf Se você definir "android-background" em seu Activity1 Layout.xml, não funcionará perfeitamente, mas funcionará.
Eu defini em meu teste: android: background = "@ android: color / transparent "

@LuizGadao Se você definir um fundo você perde todas as vantagens da biblioteca. Acho que é inútil como você quer para imagens baixadas da internet. Não para recursos estáticos como pano de fundo.
Depois de testar algumas bibliotecas, o picasso está funcionando bem para mim. Sem problemas.

@jorgemf eu concordo com você. É apenas um hack para fazer funcionar.

Algumas notícias sobre este?

@LuizGadao você pode postar um exemplo de seu XML de solução alternativa?

Obrigado por relatar este problema e apreciamos sua paciência. Notificamos a equipe principal para uma atualização sobre este problema. Esperamos uma resposta nos próximos 30 dias ou o problema pode ser resolvido.

Algumas notícias sobre este?

PS:
TranslateDraweeView fornecido por @goodev não funciona corretamente em alguns dispositivos como XiaoMi2, HuaWei P8. ReenterTransition começa na posição errada.

Como disse o boxcounter, Tra slateDraweeView não funciona no HTC One M8, nem

Se você estiver usando a transição ChangeImageTransform, então acho que a transição do elemento de compartilhamento falha porque ChangeImageTransform está animando a matriz de ImageView, que acho que não é compatível por padrão com DraweeView.

O problema que encontrei é que o elemento compartilhado começa com "fitCenter" enquanto originalmente era "centerCrop".
O projeto pode reproduzir o problema
https://github.com/JackFan-Z/ActivitySharedElementTransition.git

Embora eu tenha adicionado uma solução alternativa
não funciona no meu outro projeto privado usando afresco.
Alguém poderia descobrir onde está o verdadeiro problema?

Estado de transição errado
2015-10-01 11 26 34

Antes da transição
2015-10-01 11 26 50

@ JackFan-Z
Compartilhar elemento na transição é definir a visualização final para os valores iniciais e animá-la para os valores finais.

ImageView normal combinado com ChangeImageTransform irá capturar os valores inicial e final da matriz da imagem e então animar a mudança da matriz da imagem.

No entanto, DraweeView substitui certas funções relacionadas à matriz da imagem, de forma que ChangeImageTransform não terá nenhum efeito na imagem.

Então, o que você acaba sendo apenas ChangeBounds entrando em vigor.

Atualmente, não encontrei nenhuma maneira de manipular a matriz de imagem de DraweeView. Até mesmo setActualImageMatrix foi marcado como obsoleto. Vamos supor que ele não esteja obsoleto e funcione exatamente como o setImageMatrix padrão do ImageView padrão. Mesmo assim, não é realmente muito conivente animar a mudança dela devido ao fato de que você não tem como mudar a matriz depois de definir DraweeViewHierarchy . Então, você precisa criar um novo DraweeViewHierarchy a cada onAnimationUpdate chamada.

Eu não sei por que DraweeView implementar desta forma. E eu acho que a solução possível atual é recuperar o Bitmap subjacente e criar outro ImageView para fazer a ChangeImageTransform Transição.

@soapsign
Obrigado por seu comentário.

Na verdade, em meu projeto privado, tentei criar um ImageView fictício que usa o mesmo bitmap como elemento compartilhado. O problema ainda existe.
Não tenho certeza se o problema que estou enfrentando está relacionado ao fresco ou não.
Mas com certeza posso reproduzir o mesmo problema facilmente com SimpleDraweeView.

O ChangeImageTransform usa as dimensões intrínsecas para determinar a matriz de transformação. Nossa implementação de DraweeView usa um DraweeHierarchy que possui dimensões intrínsecas iguais a -1 para width e height . Isso ocorre porque Drawee já aplica a escala do tipo de escala correto e, portanto, não há necessidade de uma visualização para fazê-lo. Além disso, ImageView só pode aplicar um tipo de escala, enquanto a hierarquia drawable pode usar tipos de escala separados para cada ramificação da imagem (placeholder, imagem de falha, imagem real, etc.). Retornar dimensões intrínsecas reais à exibição apenas coloca como risco de ter bugs de dimensionamento.
Se você quiser que a transição funcione, você deve usar ChangeBounds .

Que tal adicionar uma nova opção como " fresco: ImageMatrixSrc = atual "?

@boxcounter No momento achamos que o que temos agora está ok. Mas você pode criar uma solicitação pull para sua proposta :)

@massimocarli ChangeBounds funciona bem apenas quando a imagem compartilhada tem o mesmo tamanho em ambas as atividades / visualizações. Mas quando a imagem deve ser redimensionada durante a transição, ela é cortada e fica ruim.
O que você se propõe a fazer dessa forma? ChangeImageTransform resolve isso, mas não funciona em DraweeView.

Mesmo aqui...

@massimocarli ChangeBounds não é bom o suficiente.

Isso é o que estou tentando alcançar (isso é usando ImageView): https://gfycat.com/HideousEarlyAndalusianhorse

Isso é o que parece usando SimpleDraweeView: https://gfycat.com/PracticalCorruptGrouper
Observe a maneira como a imagem original é redimensionada incorretamente atrás da imagem animada.

Isso é o que parece apenas com ChangeBounds como a transição: https://gfycat.com/SorrowfulExemplaryAntlion

Ei pessoal, eu tenho o mesmo problema. ChangeBounds não está funcionando bem. Se houver uma solução alternativa ou solução, informe-nos. A transição de elementos compartilhados é uma das melhores coisas que o material design introduziu e o fresco é uma das melhores bibliotecas que usei até agora. Por favor, deixe os desenvolvedores usarem ambos perfeitamente.

Alguém conseguiu encontrar uma solução alternativa, visto que o Fresco não corrige isso?

Aqui está a solução alternativa que utilizo que funciona bem:
https://github.com/bumptech/glide

Olá pessoal,

O método ChangeBounds em si não é suficiente e estou surpreso com a resposta do Facebook de que o estado atual das transições de elementos compartilhados está ok.

Finalmente encontrei uma solução simples que parece funcionar para mim em um projeto de amostra.
Uma vez que a transição ChangeBounds não atualiza o próprio layout por meio de onMeasure (), mas por meio de onSizeChanged (), que atualmente não é anulado por nenhuma vista de desenho, a escala do drawable nunca é atualizada durante a transição.

Aqui está nosso CustomDraweeView, que atualiza o TopLevelDrawable durante a transição:

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);
        }
    }
}

Aqui está o xml do conjunto de transições que você precisará aumentar:

<?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>

A única desvantagem que tenho com esse método é quando o tipo de escala dos drawables não corresponde entre os fragmentos ou as atividades, o que você deve evitar de qualquer maneira se quiser usar transições de elementos compartilhados.

@massimocarli @tyronen
Alguém no Facebook pode fornecer algumas dicas de por que DraweeView não substitui esse método atualmente e os possíveis problemas que podem surgir com essa modificação? Se nenhum for encontrado, ficarei feliz em criar uma solicitação de pull para isso.

Olá a todos! Na nova versão do Fresco 0.10 com a transformação ScaleType personalizada entre diferentes ScaleTypes é trivial. Aqui está minha implementação
https://gist.github.com/burzumrus/a589aa7e36ca003ddaf2334218c50ad0

O uso é simples

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

@burzumrus isso é incrível! Obrigado por implementá-lo. Isso é exatamente o que eu tinha em mente com InterpolatingScaleType . Considere fazer uma solicitação de pull para Fresco, se ainda não tiver feito.

@plamenko estou usando o fresco 0.12 e

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

A animação está funcionando perfeitamente. Mas, no retorno à primeira atividade, a imagem está desaparecendo

Alguém tentou fazer isso com animações de fragmento a fragmento? Porque não parece funcionar na v0.12.
Edit : é possível que o RecyclerView cause problemas?
Edição 2 : Parece que o problema é que ChangeBounds si só usa as coordenadas X e Y _window_ se a redefinição estiver definida como verdadeira. Configurá-lo por meio de ChangeBounds 's setReparenting(true) está obsoleto e ChangeTransform é recomendado em seu lugar. Portanto, para RecyclerView , transitionSet.addTransition(new ChangeTransform()); também é necessário. (A animação de retorno ainda parece ruim, mas pelo menos a animação de entrada está bem ( exceto que o tipo de escala não tem efeito mudando startValues.view para endValues.view em createAnimator(...) resolve isso) com isto.)

@Gericop e @ ladia12 0.12 funcionam bem no meu projeto em animações fragmento a fragmento.
Eu também o uso no RecyclerView.
O fato é que você só pode usar a transação de fragmento 'substituir'. Você não pode usar a transação 'adicionar'.
Se isso pode ajudá-lo, aqui está um exemplo (sem afresco) de transição fragmento a fragmento que me ajudou a começar em algo que funcionou (você pode baixar o código do projeto no github)
http://www.androidauthority.com/using-shared-element-transitions-activities-fragments-631996/

@sperochon Eu uso substituir e está em um RecyclerView, mas não funciona (e honestamente, é surpreendente que funcione para você, talvez você use uma versão diferente do RecyclerView? Eu ​​uso a v24.1.1). Tive que fazer algumas alterações para fazer as animações funcionarem:

  • adicionou ChangeTransform ao conjunto de transição por meio de transitionSet.addTransition(new ChangeTransform());

    • isso se deve ao fato de que ChangeBounds relata a posição incorreta da visualização inicial em um RecyclerView (ele sempre retorna as coordenadas X, Y do primeiro elemento)

  • em createAnimator(...) substitua if (mFromScale == mToScale) por if(mFromScale == mToScale && startBounds.equals(endBounds))

    • a transformação não acontecerá de outra forma se os dois sacados compartilharem o mesmo tipo de escala, mesmo que seus tamanhos não sejam os mesmos

  • em createAnimator(...) substitua final GenericDraweeView draweeView = (GenericDraweeView) startValues.view; por final GenericDraweeView draweeView = (GenericDraweeView) endValues.view; (lembre-se da mudança de startValues -> endValues )

    • use o sacado final em vez do inicial

  • em AnimatorUpdateListener após a chamada scaleType.setValue(fraction) , insira as seguintes linhas:
Drawable drawable = draweeView.getTopLevelDrawable();

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

Esta última parte do código é baseada na solução de @Aohayou (porque eu não consegui fazer CustomDraweeView funcionar).
Testado no Android 5.0.2 com suporte à versão lib v24.1.1.

NOTE que esta solução não funcionará se você fizer uma animação entre imagens com os mesmos tamanhos.

@Gericop Aqui está uma demonstração de que funciona bem. Acabei de enviá-lo para o github. Tentei limpar o código no máximo. Cuidado: usei apenas 1 imagem em minha visualização da recicladora porque o nome da transição deve ser diferente em cada item da visualização da recicladora para que o Fresco funcione. Então, para simplificar, usei apenas 1 imagem com 1 nome de transição.
https://github.com/sperochon/DemoFrescoFragment2Fragment

Espero que esta ajuda!

@sperochon Experimente com várias imagens.
A propósito, testei sua demonstração com fonte não modificada. Este é o resultado:

device-2016-08-14-220810_1

Isso está completamente errado. A vista final começa em uma posição diferente e o tipo de escala não tem efeito algum. Não sei como você pode dizer que "funciona bem" porque claramente não funciona.

@Gericop Acabei de atualizar o código. Esqueci de especificar um layout diferente para o fragmento final. Tente de novo por favor.

@sperochon No emulador API 23, funciona bem. No meu dispositivo (API 21) isso não acontece. Também testei em um emulador API 21, também não funciona lá.
Portanto, a questão é: a implementação atual não funciona na API 21 (não a testei na API 22), mas funciona na API 23.

Editar : sua demonstração testa apenas as transições ChangeBounds e ChangeTransform padrão, não a implementação DraweeTransition fornecida pelo Facebook.

Infelizmente, você está certo ... Eu testei em meus dispositivos:
Android 5.0 + Fresco v0.11 / v0.12 -> KO
Android 6.0 + Fresco v0.11 / v0.12 -> OK
Não tinha percebido antes ...

@Gericop @sperochon Escrevi um post no

@ ladia12 Essa postagem não tem nada a ver com o problema que eu estava (estávamos) enfrentando ... Sua entrada no blog é sobre a transição _inter- Activity _, enquanto meu problema está relacionado a _inter- Fragment _. Além disso, o verdadeiro bug está em como a API 21 lida com as transições ChangeBounds e / ou ChangeTransform onde o Facebook forneceu DraweeTransition também não ajuda. Minha solução, por outro lado, supera isso, se as imagens de origem e destino tiverem dimensões diferentes (largura e / ou altura).

Apenas para informação:
Android 5.0 + Fresco v0.11 / v0.12 / 0.13 -> KO
Android> = 5.1 + Fresco v0.11 / 0.12 / 0.13 -> OK

@ ladia12 Como você resolveu o problema do desaparecimento da imagem original ao retornar para a primeira atividade?

@dbrant Estou com o mesmo problema, encontrou uma maneira de resolver?

Veja # 1446

@ ladia12 Como você resolveu o problema do desaparecimento da imagem original ao retornar para a primeira atividade?

@ ladia12 Como você resolveu o problema do desaparecimento da imagem original ao retornar para a primeira atividade? Minha imagem original está no visor do Recyclerview

Acabei usando o Picasso para a transição do elemento compartilhado. Não foi consertado
em Fresco. Então, Picasso é leve e não há nenhum problema em usá-lo
junto com Fresco.

Na quarta-feira, 19 de junho de 2019 às 17:11 bembem1011 [email protected] escreveu:

@ ladia12 https://github.com/ladia12 Como você resolveu o problema de
a imagem original desaparecendo ao retornar para a primeira atividade? Meu
a imagem original está no visor do Recyclerview

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/facebook/fresco/issues/22?email_source=notifications&email_token=AAXQ5WYUP5KBJYNBOZX7CCDP3ILM5A5CNFSM4A6ZMH32YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYBSZCI#issuecomment-503524489 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/AAXQ5W5EXO5SV4R2PXVTG7LP3ILM5ANCNFSM4A6ZMH3Q
.

Esta página foi útil?
0 / 5 - 0 avaliações