Ao projetar o aplicativo para ser compatível com uma extensa gama de tamanhos de tela, você poderá reutilizar os fragmentos em diferentes configurações de layout para otimizar a experiência do usuário com base no espaço de tela disponível.
Por exemplo, em um celular, pode ser apropriado exibir somente um fragmento por vez para uma interface do usuário de painel simples. Reciprocamente, você pode querer arranjar fragmentos lado a lado em um tablet que tem uma tela maior para exibir mais informações ao usuário.
Figura 1. Dois fragmentos, exibidos em diferentes configurações para a mesma atividade em diferentes tamanhos de tela. Em uma tela grande, ambos os fragmentos encaixam lado a lado, mas, em um celular, somente um fragmento encaixa por vez. Portanto, os fragmentos devem substituir-se mutuamente à medida que o usuário navega.
A classe FragmentManager fornece métodos que permitem a adição,
a remoção e a substituição de fragmentos em uma atividade em tempo de execução para criar uma experiência dinâmica.
Adicionar um fragmento a uma atividade em tempo de execução
Em vez de definir os fragmentos para uma atividade no arquivo de layout—como mostrado
na lição anterior com o elemento <fragment>—você pode adicionar
um fragmento à atividade durante o tempo de execução dela. Isso é necessário
se você planeja alterar fragmentos durante a vida de uma atividade.
Para realizar uma transação como adicionar ou
remover um fragmento, você deve usar a FragmentManager para criar uma
FragmentTransaction, que fornece APIs para adicionar, remover, substituir
e realizar outras transações de fragmentos.
Se sua atividade permite que os fragmentos sejam removidos e substituídos, você deve adicionar
os fragmentos iniciais à atividade durante o método
onCreate().
Uma regra importante ao lidar com fragmentos— especialmente ao adicioná-los em
tempo de execução—é que o layout da atividade deve incluir uma View
de contêiner na qual você pode inserir o fragmento.
O layout a seguir é uma alternativa ao layout que exibe somente um fragmento por vez, mostrado na lição anterior. Para substituir
um fragmento por outro, o layout da atividade
inclui um FrameLayout vazio que age como o contêiner do fragmento.
Observe que o nome do arquivo é o mesmo que o do arquivo de layout da lição anterior, mas o diretório
de layout não tem o qualificador large, e esse layout é usado quando
a tela do dispositivo é menor que grande porque a tela não exibe dois fragmentos
ao mesmo tempo.
res/layout/news_articles.xml:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Dentro da atividade, chame getSupportFragmentManager() para obter um FragmentManager usando as APIs da Biblioteca de Suporte. Em seguida, chame beginTransaction() para criar uma FragmentTransaction e add() para adicionar um fragmento.
Você pode realizar diversas transações de fragmentos para a atividade usando a mesma FragmentTransaction. Quando estiver pronto para fazer as mudanças, você deverá chamar
commit().
Por exemplo, eis como adicionar um fragmento ao layout anterior:
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
// Create a new Fragment to be placed in the activity layout
HeadlinesFragment firstFragment = new HeadlinesFragment();
// In case this activity was started with special instructions from an
// Intent, pass the Intent's extras to the fragment as arguments
firstFragment.setArguments(getIntent().getExtras());
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
}
}
}
Em virtude de o fragmento ter sido adicionado ao contêiner FrameLayout
em tempo de execução — em vez de ser definido no layout da atividade com um elemento <fragment> —,
a atividade pode remover o fragmento e substituí-lo por um diferente.
Substituir um fragmento por outro
O procedimento para substituir um fragmento é similar ao de adicionar um, mas requer o método replace() em vez de add().
Tenha em mente que, ao realizar transações de fragmento, como substituição ou remoção, é
quase sempre apropriado permitir que o usuário navegue retornando e “desfaça” a alteração. Para permitir que o usuário
acesse transações de fragmento anteriores, você deve chamar addToBackStack() antes de acionar a
FragmentTransaction.
Observação: Ao remover ou substituir um fragmento e adicionar a transação à pilha de retorno, o fragmento removido será pausado (e não destruído). Se o usuário navegar de volta para restaurar o fragmento, ele reiniciará. Se você não adicionar a transação à pilha de retorno, o fragmento será destruído quando for removido ou substituído.
Exemplo de substituição de um fragmento por outro:
// Create fragment and give it an argument specifying the article it should show ArticleFragment newFragment = new ArticleFragment(); Bundle args = new Bundle(); args.putInt(ArticleFragment.ARG_POSITION, position); newFragment.setArguments(args); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack so the user can navigate back transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
O método addToBackStack() tem
um parâmetro de string opcional que especifica um nome único para a transação. O nome não é
necessário a menos que você planeje realizar operações de fragmento avançadas usando as APIs FragmentManager.BackStackEntry.