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

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>

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.


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


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.


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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.