Transações de fragmentos

No momento da execução, um FragmentManager pode adicionar, remover, substituir e realizar outras ações com fragmentos em resposta à interação do usuário. Cada conjunto de mudanças de fragmentos confirmado é chamado de transação. É possível especificar o que será feito dentro da transação usando as APIs fornecidas pela classe FragmentTransaction. Você pode agrupar várias ações em uma única transação. Por exemplo, uma transação pode adicionar ou substituir vários fragmentos. Esse agrupamento pode ser útil quando há vários fragmentos irmãos exibidos na mesma tela, como ocorre com visualizações divididas.

Também é possível salvar cada transação em uma pilha de retorno gerenciada pelo FragmentManager, permitindo que o usuário retorne para as mudanças de fragmentos anteriores, de forma semelhante à navegação inversa pelas atividades.

É possível conseguir uma instância de FragmentTransaction do FragmentManager chamando beginTransaction(), conforme mostrado no exemplo a seguir:

Kotlin

val fragmentManager = ...
val fragmentTransaction = fragmentManager.beginTransaction()

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

A chamada final em cada FragmentTransaction precisa confirmar a transação. A chamada commit() indica ao FragmentManager que todas as operações foram adicionadas à transação.

Kotlin

val fragmentManager = ...
// The fragment-ktx module provides a commit block that automatically
// calls beginTransaction and commit for you.
fragmentManager.commit {
    // Add operations here
}

Java

FragmentManager fragmentManager = ...
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

// Add operations here

fragmentTransaction.commit();

Permitir a reordenação de mudanças de estado do fragmento

Cada FragmentTransaction precisa usar setReorderingAllowed(true):

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

Java

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

Para compatibilidade de comportamento, a sinalização de reordenação não está ativada por padrão. No entanto, é necessário permitir que FragmentManager execute a FragmentTransaction de forma adequada, principalmente quando ele opera na pilha de retorno e executa animações e transições. Ativar a sinalização garante que, se várias transações forem executadas juntas, os fragmentos intermediários (ou seja, aqueles que foram adicionados e substituídos imediatamente) não passarão por mudanças de ciclo de vida nem terão animações ou transições executadas. Essa sinalização afeta a execução inicial da transação e a reversão da transação com popBackStack().

Adicionar e remover fragmentos

Para adicionar um fragmento a um FragmentManager, chame add() na transação. Esse método recebe o ID do contêiner do fragmento, assim como o nome da classe do fragmento que você quer adicionar. O fragmento adicionado é movido para o estado RESUMED. É altamente recomendável que o contêiner seja uma FragmentContainerView que faça parte da hierarquia de visualização.

Para remover um fragmento do host, chame remove(), transmitindo uma instância de fragmento que foi recuperada do gerenciador de fragmentos por findFragmentById() ou findFragmentByTag(): Se a visualização do fragmento tiver sido adicionada anteriormente a um contêiner, ela será removido do contêiner. O fragmento removido é movido ao estado DESTROYED.

Use replace() para substituir um fragmento existente em um contêiner por uma instância de uma nova classe de fragmentos fornecida. Chamar replace() equivale a chamar remove() com fragmento em um contêiner e adicionar um novo fragmento a esse mesmo contêiner.

O snippet de código a seguir mostra como substituir um fragmento por outro:

Kotlin

// Create new fragment
val fragmentManager = // ...

// Create and commit a new transaction
fragmentManager.commit {
    setReorderingAllowed(true)
    // Replace whatever is in the fragment_container view with this fragment
    replace<ExampleFragment>(R.id.fragment_container)
}

Java

// Create new fragment and transaction
FragmentManager fragmentManager = ...
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setReorderingAllowed(true);

// Replace whatever is in the fragment_container view with this fragment
transaction.replace(R.id.fragment_container, ExampleFragment.class, null);

// Commit the transaction
transaction.commit();

Nesse exemplo, uma nova instância de ExampleFragment substitui o fragmento, se houver, que está atualmente no contêiner de layout identificado por R.id.fragment_container.

Por padrão, as mudanças feitas em uma FragmentTransaction não são adicionadas à pilha de retorno. Para salvar essas mudanças, chame addToBackStack() na FragmentTransaction. Para ver mais informações, consulte Gerenciador de fragmentos.

A confirmação é assíncrona

Ao chamar commit(), a transação não será realizada imediatamente. Em vez disso, a transação é programada na principal linha de execução de IU para ser executada assim que possível. No entanto, se necessário, você pode chamar commitNow() para executar a transação de fragmento imediatamente na linha de execução de IU.

commitNow é incompatível com addToBackStack. Como alternativa, é possível executar todas as FragmentTransactions pendentes enviadas por chamadas commit() que ainda não foram executadas, chamando executePendingTransactions(). Essa abordagem é compatível com addToBackStack.

Para a grande maioria dos casos de uso, você só precisa de commit().

A ordem da operação é importante

A ordem em que você realiza operações em uma FragmentTransaction é importante, especialmente ao usar setCustomAnimations(). Esse método aplica as animações fornecidas a todas as operações de fragmento que o seguem.

Kotlin

supportFragmentManager.commit {
    setCustomAnimations(enter1, exit1, popEnter1, popExit1)
    add<ExampleFragment>(R.id.container) // gets the first animations
    setCustomAnimations(enter2, exit2, popEnter2, popExit2)
    add<ExampleFragment>(R.id.container) // gets the second animations
}

Java

getSupportFragmentManager().beginTransaction()
        .setCustomAnimations(enter1, exit1, popEnter1, popExit1)
        .add(R.id.container, ExampleFragment.class, null) // gets the first animations
        .setCustomAnimations(enter2, exit2, popEnter2, popExit2)
        .add(R.id.container, ExampleFragment.class, null) // gets the second animations
        .commit()

Limitar o ciclo de vida do fragmento

As FragmentTransactions podem afetar o estado do ciclo de vida de fragmentos individuais adicionados ao escopo da transação. Ao criar uma FragmentTransaction, setMaxLifecycle() define um estado máximo para o fragmento especificado. Por exemplo, ViewPager2 usa setMaxLifecycle() para limitar os fragmentos fora da tela ao estado STARTED.

Como exibir e ocultar visualizações do fragmento

Use os métodos show() e hide() da FragmentTransaction para exibir e ocultar a visualização de fragmentos que foram adicionados a um contêiner. Esses métodos definem a visibilidade das visualizações do fragmento sem afetar o ciclo de vida dele.

Embora não seja necessário usar uma transação de fragmento para alternar a visibilidade das visualizações em um fragmento, esses métodos são úteis para casos em que você quer que as mudanças no estado de visibilidade sejam associadas a transações na pilha de retorno.

Como anexar e remover fragmentos

O método detach() da FragmentTransaction separa o fragmento da IU, eliminando a hierarquia de visualização. O fragmento permanece no mesmo estado (STOPPED) quando é colocado na pilha de retorno. Isso significa que o fragmento foi removido da IU, mas ainda é gerenciado pelo gerenciador de fragmentos.

O método attach() anexa novamente um fragmento que já foi removido. Isso faz com que a hierarquia de visualização seja recriada, anexada à IU e exibida.

Como uma FragmentTransaction é tratada como um único conjunto atômico de operações, as chamadas para detach e attach na mesma instância de fragmento na mesma transação cancelam efetivamente umas às outras, a fim de evitar a destruição e a recriação imediata da IU do fragmento. Caso você queira remover e, em seguida, imediatamente anexar mais uma vez um fragmento, use transações separadas, divididas por executePendingOperations() se estiver usando commit().