Animar a transição entre fragmentos

284

Estou tentando animar a transição entre fragmentos. Eu recebi a resposta dos seguintes
fragmentos e animação do Android

FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.slide_in_left, R.anim.slide_out_right);

DetailsFragment newFragment = DetailsFragment.newInstance();

ft.replace(R.id.details_fragment_container, newFragment, "detailFragment");

// Start the animated transition.
ft.commit();

E meu R.anim.slide_in_left

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
        <translate android:fromXDelta="50%p" android:toXDelta="0"
            android:duration="@android:integer/config_mediumAnimTime"/>
       <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
            android:duration="@android:integer/config_mediumAnimTime" />
</set>

Mas quando eu tentei isso, mostrou

02-08 16:27:37.961: ERROR/AndroidRuntime(1717): FATAL EXCEPTION: main
02-08 16:27:37.961: ERROR/AndroidRuntime(1717): java.lang.RuntimeException: Unknown animator name: translate
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:129)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:126)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.createAnimatorFromXml(AnimatorInflater.java:93)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.animation.AnimatorInflater.loadAnimator(AnimatorInflater.java:72)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.loadAnimator(FragmentManager.java:621)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:733)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.BackStackRecord.run(BackStackRecord.java:578)
02-08 16:27:37.961: ERROR/AndroidRuntime(1717):     at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1217)

Alguma ideia? Quando chequei a referência da API do Honeycomb, translateexiste. Do que eu senti falta?
Existe alguma outra maneira de animar a transição entre fragmentos? Obrigado

Labeeb Panampullan
fonte
use ANIMATOR --- não Animação! use android.R.ANIMATOR.fade_in funciona, NÃO use android.R.ANIM.fade_in - ele tem um comportamento BUGS
user1269737 2/18

Respostas:

347

Você precisa usar a nova android.animationestrutura (animadores de objeto) e FragmentTransaction.setCustomAnimationstambém FragmentTransaction.setTransition.

Aqui está um exemplo de uso setCustomAnimationsdo FragmentHideShow.java do ApiDemos :

ft.setCustomAnimations(android.R.animator.fade_in, android.R.animator.fade_out);

e aqui está o XML do animador relevante em res / animator / fade_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:interpolator/accelerate_quad"
    android:valueFrom="0"
    android:valueTo="1"
    android:propertyName="alpha"
    android:duration="@android:integer/config_mediumAnimTime" />

Observe que você pode combinar vários animadores usando <set>, da mesma maneira que poderia com a estrutura de animação mais antiga.


Edição : Como as pessoas estão perguntando sobre slide-in / slide-out, vou comentar sobre isso aqui.

Deslize para dentro e para fora

Pode, claro, animar os translationX, translationY, x, e ypropriedades, mas geralmente lâminas envolvem animar conteúdo de e para fora da tela. Tanto quanto sei, não existem propriedades de transição que usem valores relativos. No entanto, isso não impede que você os escreva. Lembre-se de que as animações de propriedades simplesmente requerem métodos getter e setter nos objetos que você está animando (neste caso, visualizações), para que você possa criar seus próprios métodos getXFractione setXFractionmétodos na subclasse de visualização, desta forma:

public class MyFrameLayout extends FrameLayout {
    ...
    public float getXFraction() {
        return getX() / getWidth(); // TODO: guard divide-by-zero
    }

    public void setXFraction(float xFraction) {
        // TODO: cache width
        final int width = getWidth();
        setX((width > 0) ? (xFraction * width) : -9999);
    }
    ...
}

Agora você pode animar a propriedade 'xFraction', assim:

res / animador / slide_in.xml :

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/linear_interpolator"
    android:valueFrom="-1.0"
    android:valueTo="0"
    android:propertyName="xFraction"
    android:duration="@android:integer/config_mediumAnimTime" />

Observe que, se o objeto em que você está animando não tiver a mesma largura que seu pai, as coisas não parecerão bem; portanto, talvez você precise ajustar a implementação da propriedade para se adequar ao seu caso de uso.

Roman Nurik
fonte
8
Eu tenho o fade_in e o fade_out para trabalhar, mas os outros no / res / animator dão erros. E nenhum deles parece ser para entrar e sair. Eu tentei escrever meus próprios xmls para fazer isso, mas tudo o que acabo com são fragmentos em cima de fragmentos. Mais alguma ajuda, por favor?
Dave MacLean
E a tradução? Como você faz uma tradução com valores em porcentagem em um objectAnimator definido em XML, por favor? Eu não conseguiram animar AdapterViewFlipper durante lançando com animações de slides verticais definir em XML ...
GBouerat
6
Estou recebendo 11-19 10: 27: 50.912: W / PropertyValuesHolder (23107): Método setXFraction () com tipo float não encontrado na classe de classe android.widget.FrameLayout da classe de destino. Mas, no meu XML, tenho minha exibição personalizada MyFrameLayout. Alguma ideia?
Barkside
13
Na verdade, Roman, o conselho deve ir para o outro lado também: Ao utilizar a Biblioteca de suporte, você precisa usar o antigo quadro de animação (android.R.anim) com FragmentTransaction.setCustomAnimations Ao
pjv
1
@RomanNurik, esta resposta funcionou muito bem na maioria dos dispositivos, mas para alguns usuários (especificamente em alguns telefones Samsung Galaxy S3 / 4) a largura não estava sendo relatada durante as animações por algum motivo, fazendo com que o fragmento nunca aparecesse. Eu era capaz de fazê-lo funcionar para aqueles usuários que utilizam um OnPredrawListener como mostrado aqui: mavyasoni9891.blogspot.com/2014/06/...
ajpolt
188

Eu fiz assim:

Adicione este método para substituir fragmentos por animações :

public void replaceFragmentWithAnimation(android.support.v4.app.Fragment fragment, String tag){
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
    transaction.replace(R.id.fragment_container, fragment);
    transaction.addToBackStack(tag);
    transaction.commit();
}

Você precisa adicionar quatro animações na pasta anim associada ao recurso :

enter_from_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="-100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

exit_to_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

enter_from_right.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="100%" android:toXDelta="0%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700" />
</set>

exit_to_left.xml :

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="false">
    <translate
        android:fromXDelta="0%" android:toXDelta="-100%"
        android:fromYDelta="0%" android:toYDelta="0%"
        android:duration="700"/>
</set>

Resultado:

insira a descrição da imagem aqui

Está feito .

Hiren Patel
fonte
14
Ótima solução. No entanto, não sei por que você trocou as instruções para RTL. Meu método:.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right)
zed 17/05
2
Solução impressionante. Abordagem semelhante e os mesmos arquivos de animação funcionam para transições entre atividades.
Stan
1
@MikeZriel, res -> anim -> colocar o xml aqui
Hiren Patel
3
Obrigado Hiren, altero a velocidade (700) para (300) muito melhor e mais parecida com iOS #
Mike Zriel
3
LOL, voltei com solução. Eu estava importando android.app.fragment e FragmentManager em cada classe java. Após verificar alguns materiais, descobri que o uso do 'setCustomAnimations ()' precisa que a biblioteca android.support.v4 seja importada. importante dizer que deve ser 'support.v4.app'! Substituí todos os métodos 'getFragmentManager ()' por 'getSupportFragmentManager ()' e toda a importação 'android.app.Fragment / FragmentManager ...' para 'android.support.v4.app ....'; a animação começou a funcionar bem sem falhas ... Se vocês estão presos em casos semelhantes, leia minha solução. Thx Hiren Patel xD
KoreanXcodeWorker
58

Se você pode se dar ao luxo de usar apenas o Lollipop e mais tarde, isso parece funcionar:

import android.transition.Slide;
import android.util.Log;
import android.view.Gravity;
.
.
.
f = new MyFragment();
f.setEnterTransition(new Slide(Gravity.RIGHT));
f.setExitTransition(new Slide(Gravity.LEFT));
getFragmentManager()
    .beginTransaction()
    .replace(R.id.content, f, FRAG_TAG)  // FRAG_TAG is the tag for your fragment
    .commit();

Espero que isto ajude.

scorpiodawg
fonte
1
Embora isso seja alcançado no Lollipop, dificilmente é prático, pois a porcentagem de dispositivos executando o Lollipop é insignificante (atualmente 1,6% dos dispositivos Android estão executando o Lollipop).
Eran Goldin
1
new Slide(...): chamada requer nível API 21
Chintan Soni 21/12
o que getKey () significa?
Alvaro
13
@EranGoldin Nada dura para sempre ... você zombaria de uma solução única para Android 2.0 ou superior hoje?
Tom
@ Tom você tem razão. No entanto, quando seu aplicativo tem uma grande base de usuários, você não pode simplesmente aumentar o nível da API. Se a maioria dos usuários não conseguir mais executar seu aplicativo depois, isso não será uma solução.
Eran Goldin
47

A resposta de Nurik foi muito útil, mas não consegui fazê-la funcionar até encontrar isso . Em resumo, se você estiver usando a biblioteca de compatibilidade (por exemplo, SupportFragmentManager em vez de FragmentManager), a sintaxe dos arquivos de animação XML será diferente.

strangeluck
fonte
28

Aqui está uma animação de slide in / out entre fragmentos:

FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.animator.enter_anim, R.animator.exit_anim);
transaction.replace(R.id.listFragment, new YourFragment());
transaction.commit();

Estamos usando um objectAnimator.

Aqui estão os dois arquivos xml na subpasta animador .

enter_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
     <objectAnimator
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:duration="1000"
         android:propertyName="x"
         android:valueFrom="2000"
         android:valueTo="0"
         android:valueType="floatType" />
</set>

exit_anim.xml

<?xml version="1.0" encoding="utf-8"?>
<set>
    <objectAnimator
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="1000"
        android:propertyName="x"
        android:valueFrom="0"
        android:valueTo="-2000"
        android:valueType="floatType" />
</set>

Espero que ajude alguém.

kirilv
fonte
37
mover a visualização para 2000 px é uma solução muito feia.
Carlo.marinangeli
4
O exit_anim simplesmente "sai" da tela para mim, não volta a aparecer na tela. Alguma ideia? Estou usando.setCustomAnimations(R.animator.slide_in_left, R.animator.slide_out_right, R.animator.slide_in_left, R.animator.slide_out_right)
Sr. Pablo
@ MrPablo, o motivo provavelmente é que você não copiou e colou o código acima. setCustomAnimations deve ser chamado antes do método de substituição.
Galya
Nesse caso, se eu substituir outro fragmento por animação e minimizar o aplicativo imediatamente antes que o tempo limite ou a duração da animação retorne novamente ao aplicativo, ele exibirá o fragmento anterior e o fragmento atual paralelos.
Prince
23

Para quem for pego, verifique se setCustomAnimations é chamado antes da chamada para substituir / adicionar ao criar a transação.

Charlie
fonte
12

A implementação do FragmentTransaction no Android SDK quer um Animatortempo enquanto a biblioteca de suporte quer um Animation, não me pergunte por que, mas depois do comentário do strangeluk, olhei para o código do Android 4.0.3 e a biblioteca de suporte. Usos do SDK do Android loadAnimator()e da biblioteca de suporteloadAnimation()

sherpya
fonte
7

Tente usar esta solução simples e em jejum. O Android fornece alguns animations padrão .

fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
fragmentManager.addOnBackStackChangedListener(this);
fragmentTransaction.replace(R.id.frame, firstFragment, "h");
fragmentTransaction.addToBackStack("h");
fragmentTransaction.commit();

Resultado:

insira a descrição da imagem aqui

Gowthaman M
fonte
Uau .. essa deve ser a resposta aceita !! Uma solução simples e elegante. É muito suave em comparação com as outras respostas
sugeridas