Fragmentos e animação Android

265

Como você deve implementar o tipo de deslizamento que, por exemplo, o cliente Honeycomb Gmail usa?

Para TransactionManagerlidar com isso automaticamente adicionando e removendo os fragmentos, é meio difícil testar isso porque o emulador é uma apresentação de slides :)

alexanderblom
fonte

Respostas:

388

Para animar a transição entre fragmentos ou para animar o processo de mostrar ou ocultar um fragmento, use o Fragment Managerpara criar umFragment Transaction .

Dentro de cada transação de fragmento, você pode especificar animações de entrada e saída que serão usadas para mostrar e ocultar respectivamente (ou ambas quando a substituição for usada).

O código a seguir mostra como você substituiria um fragmento deslizando um fragmento e deslizando o outro em seu lugar.

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

Para conseguir a mesma coisa ao ocultar ou mostrar um fragmento, você simplesmente chamaria ft.showou ft.hide, passando o fragmento que deseja mostrar ou ocultar, respectivamente.

Para referência, as definições de animação XML usariam a objectAnimatortag Um exemplo de slide_in_left pode ser algo como isto:

<?xml version="1.0" encoding="utf-8"?>
<set>
  <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:propertyName="x" 
    android:valueType="floatType"
    android:valueFrom="-1280"
    android:valueTo="0" 
    android:duration="500"/>
</set>
Reto Meier
fonte
57
Quando eu tentei isso, ele mostra RuntimeException: Nome desconhecido do animador: translate .
Labeeb Panampullan
3
Certifique-se de que as animações definidas em slide_in_left e right sejam construídas usando um conjunto de definições de objectAnimator em vez da antiga definição de animação.
Reto Meier
7
Isso ajudou muito. Eu estava no caminho certo, mas simplesmente não cheguei lá. Para os outros leitores, você também pode ter o android: interpolator como um atributo, com o seu favorito especificado (como "@android: interpolator / linear"). O padrão é "@android: interpolator / accelerate_decelerate".
Dave MacLean
6
Estou segmentando a API nível 7 com as APIs de compatibilidade. Existe uma maneira de eu animar fragmentos?
precisa
5
@JarrodSmith, você pode tentar usar uma biblioteca de compatibilidade como NineOldAndroids para trazer a API do Honeycomb para a Eclair.
Mr. S
249

Se você não precisar usar a biblioteca de suporte, consulte a resposta de Roman .

Mas se você quiser usar a biblioteca de suporte, precisará usar a estrutura de animação antiga, conforme descrito abaixo.

Depois de consultar as respostas de Reto e blindstuff, obtive o seguinte código funcionando.

Os fragmentos aparecem deslizando da direita e deslizando para a esquerda quando a parte traseira é pressionada.

FragmentManager fragmentManager = getSupportFragmentManager();

FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit);

CustomFragment newCustomFragment = CustomFragment.newInstance();
transaction.replace(R.id.fragment_container, newCustomFragment );
transaction.addToBackStack(null);
transaction.commit();

A ordem é importante. Isso significa que você deve ligar setCustomAnimations()antes replace()ou a animação não terá efeito!

Em seguida, esses arquivos devem ser colocados dentro da pasta res / anim .

enter.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

exit.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="-100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_enter.xml :

<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="-100%"
               android:toXDelta="0"
               android:interpolator="@android:anim/decelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

pop_exit.xml :

<?xml version="1.0" encoding="utf-8"?>
<set>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
               android:fromXDelta="0"
               android:toXDelta="100%"
               android:interpolator="@android:anim/accelerate_interpolator"
               android:duration="@android:integer/config_mediumAnimTime"/>
</set>

A duração das animações pode ser alterada para qualquer um dos valores padrão como @android:integer/config_shortAnimTimeou qualquer outro número.

Observe que, entre substituições de fragmentos, ocorre uma alteração na configuração (por exemplo, rotação) a ação de retorno não é animada. Este é um erro documentado que ainda existe na versão 20 da biblioteca de suporte.

dmanargias
fonte
47
Isso acabou de me salvar. Note, preste atenção ao pedido é importante , o que, naturalmente, eu perdi na primeira vez. Isso significa que você deve chamar setCustomAnimations () antes de substituir ().
Stephen Kidson
3
Tentei implementar em meus fragmentos. Escrevi tudo como você mencionou, mas o logcat diz: nome desconhecido do animador translate Como posso solucionar esse problema? Pelo jeito que eu estou chamando meu fragmento de navegação Drawer (Sliding Menu)
Zafer Celaloglu
Funciona muito bem, mas acontece que criar isso com as ferramentas de construção 21.1 gera um erro dizendo "Nome de arquivo inválido: deve conter apenas letras minúsculas e dígitos ([a-z0-9_.])". Sugiro editar os nomes dos arquivos na resposta para pop_enter.xml e pop_exit.xml.
smichak
Ótima solução e funciona muito bem quando pressiono o botão Voltar. Só tenho uma pergunta: se eu quiser criar um backButton personalizado, que código devo chamar para replicar o comportamento no botão Voltar?
Thomas Teilmann 5/03/15
1
Thomas se você deseja fazer backup, você deve implementar esta forma: .setCustomAnimations (R.anim.pop_enter, R.anim.pop_exit, R.anim.enter, R.anim.exit)
Alex Zaraos
26

Eu sugiro que você use isso em vez de criar o arquivo de animação, porque é uma solução muito melhor. O Android Studio já fornece o padrão que animation você pode usar sem criar nenhum novo arquivo XML. Os nomes das animações são android.R.anim.slide_in_left e android.R.anim.slide_out_right e você pode usá-los da seguinte maneira:

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
1
... coisas no android.R são diferentes em diferentes APIs.
Steve Moretz
@stevemoretz thaxs bro concordei seu ponto .. Vou corrigir e atualizar a minha resposta ...
Gowthaman M
5

Minha biblioteca de suporte modificado suporta o uso de animações de exibição (por exemplo <translate>, <rotate>) e animadores de objetos ( <objectAnimator>por exemplo) para transições de fragmentos. É implementado com NineOldAndroids . Consulte minha documentação no github para obter detalhes.

mark.kedzierski
fonte
2

Quanto a mim, preciso da diraction view:

em -> deslize da direita

fora -> deslize para a esquerda

Aqui funciona para mim código:

slide_in_right.xml

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

slide_out_left.xml

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

código da transação:

inline fun FragmentActivity.setContentFragment(
        containerViewId: Int,
        backStack: Boolean = false,
        isAnimate: Boolean = false,
        f: () -> Fragment

): Fragment? {
    val manager = supportFragmentManager
    return f().apply {
        manager.beginTransaction().let {
            if (isAnimate)
                it.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left)

            if (backStack) {
                it.replace(containerViewId, this, "Fr").addToBackStack("Fr").commit()
            } else {
                it.replace(containerViewId, this, "Fr").commit()
            }
        }
    }
}
Serg Burlaka
fonte
Android parece estar piscando as transições com essas animações (especialmente os traduzir)
Gabriel De Oliveira Rohden
@GabrielDeOliveiraRohden quanto a mim não em todos os casos #
Serg Burlaka 20/03/19
1

Eu resolvo isso da maneira Abaixo

Animation anim = AnimationUtils.loadAnimation(this, R.anim.slide);
fg.startAnimation(anim);
this.fg.setVisibility(View.VISIBLE); //fg is a View object indicate fragment
Shakawat Hossain
fonte